SupplicantWifiScannerImpl.java revision 41e38d84f562e12198f7db0d45f633712cae6cba
19ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills/*
29ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * Copyright (C) 2015 The Android Open Source Project
39ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills *
49ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * Licensed under the Apache License, Version 2.0 (the "License");
59ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * you may not use this file except in compliance with the License.
69ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * You may obtain a copy of the License at
79ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills *
89ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills *      http://www.apache.org/licenses/LICENSE-2.0
99ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills *
109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * Unless required by applicable law or agreed to in writing, software
119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * distributed under the License is distributed on an "AS IS" BASIS,
129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * See the License for the specific language governing permissions and
149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills * limitations under the License.
159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills */
169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willspackage com.android.server.wifi;
189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.app.AlarmManager;
209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.content.Context;
219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.net.wifi.ScanResult;
229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.net.wifi.WifiScanner;
239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.Handler;
249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.Looper;
259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.Message;
269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.SystemClock;
279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.util.Log;
289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport com.android.server.wifi.WifiMonitor;
309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport com.android.server.wifi.WifiNative;
319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.ArrayDeque;
339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.ArrayList;
349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Arrays;
359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Collections;
369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Comparator;
379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.HashSet;
389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.List;
399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Set;
409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willspublic class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handler.Callback {
429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final String TAG = "SupplicantWifiScannerImpl";
439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final boolean DBG = false;
449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int SCAN_BUFFER_CAPACITY = 10;
469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int MAX_APS_PER_SCAN = 32;
479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int MAX_SCAN_BUCKETS = 16;
489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final String ACTION_SCAN_PERIOD =
509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            "com.android.server.util.SupplicantWifiScannerImpl.action.SCAN_PERIOD";
519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final Context mContext;
539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final WifiNative mWifiNative;
549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final AlarmManager mAlarmManager;
559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final Handler mEventHandler;
569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private Object mSettingsLock = new Object();
589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Next scan settings to apply when the previous scan completes
609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.ScanSettings mPendingScanSettings = null;
619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.ScanEventHandler mPendingScanEventHandler = null;
629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Active scan settings
649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.ScanSettings mScanSettings = null;
659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.ScanEventHandler mScanEventHandler = null;
669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private int mNextScanPeriod = 0;
679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private int mNextScanId = 0;
689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private LastScanSettings mLastScanSettings = null;
699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private ScanBuffer mScanBuffer = new ScanBuffer(SCAN_BUFFER_CAPACITY);
709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Active hotlist settings
729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.HotlistEventHandler mHotlistHandler = null;
739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private ChangeBuffer mHotlistChangeBuffer = new ChangeBuffer();
749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
7541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills    AlarmManager.OnAlarmListener mScanPeriodListener = new AlarmManager.OnAlarmListener() {
7641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            public void onAlarm() {
7741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                // in case we never got the results of the previous scan
7841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                // make sure we start a new scan
7941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                synchronized (mSettingsLock) {
8041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    if (mLastScanSettings != null) {
8141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                        Log.w(TAG,
8241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                                "Did not get a scan results/failure event from previous scan");
8341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                        mLastScanSettings = null;
8441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    }
8541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    handleScanPeriod();
8641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
8741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
8841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        };
8941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public SupplicantWifiScannerImpl(Context context, WifiNative wifiNative, Looper looper) {
919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mContext = context;
929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mWifiNative = wifiNative;
939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mEventHandler = new Handler(looper, this);
969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
1009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
1049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_cache_size = Integer.MAX_VALUE;
1059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_buckets = MAX_SCAN_BUCKETS;
1069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_ap_cache_per_scan = MAX_APS_PER_SCAN;
1079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_rssi_sample_size = 8;
1089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_reporting_threshold = SCAN_BUFFER_CAPACITY;
1099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_hotlist_bssids = 0;
1109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_significant_wifi_change_aps = 0;
1119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        return true;
1129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean startBatchedScan(WifiNative.ScanSettings settings,
1169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.ScanEventHandler eventHandler) {
1179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings == null || eventHandler == null)
1189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings.max_ap_per_scan < 0 || settings.max_ap_per_scan > MAX_APS_PER_SCAN)
1219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings.num_buckets < 0 || settings.num_buckets > MAX_SCAN_BUCKETS)
1239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings.report_threshold_num_scans < 0 ||
1259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                settings.report_threshold_num_scans > SCAN_BUFFER_CAPACITY)
1269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings.report_threshold_percent < 0 || settings.report_threshold_percent > 100)
1289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings.base_period_ms <= 0)
1309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        for (int i = 0; i < settings.num_buckets; ++i) {
1329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.BucketSettings bucket = settings.buckets[i];
1339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (bucket.period_ms % settings.base_period_ms != 0)
1349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return false;
1359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
1369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
1389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            stopBatchedScan();
1399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            Log.d(TAG, "Starting scan num_buckets=" + settings.num_buckets + ", base_period=" +
1409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    settings.base_period_ms + " ms");
1419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mPendingScanSettings = settings;
1429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mPendingScanEventHandler = eventHandler;
1439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod(); // Try to start scan immediately
1449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
1459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
1469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void stopBatchedScan() {
1509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
1519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (DBG) {Log.d(TAG, "Stopping scan"); }
1529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mScanSettings = null;
1539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mScanEventHandler = null;
1549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mPendingScanSettings = null;
1559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mPendingScanEventHandler = null;
1569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
1579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
1589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void pauseBatchedScan() {
1629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
1639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (DBG) { Log.d(TAG, "Pausing scan"); }
1649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // if there isn't a pending scan then make the current scan pending
1659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mPendingScanSettings == null) {
1669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingScanSettings = mScanSettings;
1679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingScanEventHandler = mScanEventHandler;
1689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
1699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mScanSettings = null;
1709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mScanEventHandler = null;
1719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
1739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiScanner.ScanData[] results = getLatestBatchedScanResults(/* flush = */ true);
1759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mPendingScanEventHandler != null)
1769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingScanEventHandler.onScanPaused(results);
1779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
1789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void restartBatchedScan() {
1829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
1839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (DBG) { Log.d(TAG, "Restarting scan"); }
1849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mPendingScanEventHandler != null)
1859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingScanEventHandler.onScanRestarted();
1869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod();
1879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
1889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void unscheduleScansLocked() {
19141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        mAlarmManager.cancel(mScanPeriodListener);
1929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mLastScanSettings = null; // make sure that a running scan is marked as ended
1939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void handleScanPeriod() {
1969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
1979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mLastScanSettings != null) {
1989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
1999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
2009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // Update scan settings if there is a pending scan
2029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mPendingScanSettings != null) {
2039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mScanSettings = mPendingScanSettings;
2049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mScanEventHandler = mPendingScanEventHandler;
2059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mNextScanPeriod = 0;
2069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingScanSettings = null;
2079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingScanEventHandler = null;
2089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
2099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mScanSettings != null && mScanSettings.num_buckets > 0) {
2119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Set<Integer> freqs = new HashSet<>();
2129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; // default to no batch
2139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                for (int bucket_id = 0; bucket_id < mScanSettings.num_buckets; ++bucket_id) {
2149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    WifiNative.BucketSettings bucket = mScanSettings.buckets[bucket_id];
2159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mNextScanPeriod % (bucket.period_ms / mScanSettings.base_period_ms) == 0) {
2169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if ((bucket.report_events & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)
2179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                != 0) {
2189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            reportEvents |= WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
2199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
2209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if ((bucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)
2219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                != 0) {
2229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
2239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
2249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        // only no batch if all buckets specify it
2259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if ((bucket.report_events & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
2269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            reportEvents &= ~WifiScanner.REPORT_EVENT_NO_BATCH;
2279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
2289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (bucket.band != WifiScanner.WIFI_BAND_UNSPECIFIED) {
23041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                            WifiScanner.ChannelSpec[] channels =
23141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                                    WifiChannelHelper.getChannelsForBand(bucket.band);
23241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                            for (WifiScanner.ChannelSpec channel : channels) {
23341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                                freqs.add(channel.frequency);
2349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
2359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
2369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        else {
2379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            for (int channel_id = 0; channel_id < bucket.num_channels;
2389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                    ++channel_id) {
2399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                WifiNative.ChannelSettings channel = bucket.channels[channel_id];
2409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                freqs.add(channel.frequency);
2419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
2429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
2439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
2449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
2459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (freqs.size() > 0) {
2469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    boolean success = mWifiNative.scan(
2479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, freqs);
2489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (success) {
2499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        Log.d(TAG, "Starting wifi scan " + mNextScanId + " for " + freqs.size() +
2509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                " freqs");
2519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        mLastScanSettings = new LastScanSettings(mNextScanId++,
2529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                SystemClock.elapsedRealtime(), mScanSettings.max_ap_per_scan,
2539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                reportEvents, mScanSettings.report_threshold_num_scans,
2549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mScanSettings.report_threshold_percent);
2559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
2569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    else {
2579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        Log.w(TAG, "Failed starting wifi scan for " + freqs.size() + " freqs");
2589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
2599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
2609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mNextScanPeriod++;
2629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mAlarmManager.set(AlarmManager.RTC_WAKEUP,
2639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        System.currentTimeMillis() + mScanSettings.base_period_ms,
26441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                        "SupplicantWifiScannerImpl Period",
26541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                        mScanPeriodListener, mEventHandler);
2669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
2679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean handleMessage(Message msg) {
2729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        switch(msg.what) {
2739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_FAILED_EVENT:
2749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Log.w(TAG, "Scan failed");
2759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                synchronized (mSettingsLock) {
2769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mLastScanSettings = null;
2779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
2789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
2799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_RESULTS_EVENT:
2809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                pollLatestScanData();
2819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
2829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            default:
2839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                // ignore unknown event
2849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        return true;
2869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final Comparator<ScanResult> SCAN_RESULT_RSSI_COMPARATOR =
2899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            new Comparator<ScanResult>() {
2909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int compare(ScanResult r1, ScanResult r2) {
2919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return r2.level - r1.level;
2929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    };
2949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void pollLatestScanData() {
2959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
2969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mLastScanSettings == null || mScanSettings == null) {
2979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                 // got a scan before we started scanning or after scan was canceled
2989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
2999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (DBG) { Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId); }
3029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanDetail> nativeResults = mWifiNative.getScanResults();
3039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            List<ScanResult> scanResults = new ArrayList<>();
3049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < nativeResults.size(); ++i) {
3059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = nativeResults.get(i).getScanResult();
3069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                long timestamp_ms = result.timestamp / 1000; // convert us -> ms
3079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (timestamp_ms > mLastScanSettings.startTime) {
3089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    scanResults.add(result);
3099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                else {
3119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    // was a cached result in wpa_supplicant
3129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
31441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
31541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            if (mScanEventHandler != null) {
31641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                if ((mLastScanSettings.reportEvents &
31741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                             WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
31841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    for (ScanResult scanResult : scanResults) {
31941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                        mScanEventHandler.onFullScanResult(scanResult);
32041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    }
32141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
32241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
32341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
3249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            Collections.sort(scanResults, SCAN_RESULT_RSSI_COMPARATOR);
3259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ScanResult[] scanResultsArray =
3269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                new ScanResult[Math.min(mLastScanSettings.maxAps, scanResults.size())];
3279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < scanResultsArray.length; ++i) {
3289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                scanResultsArray[i] = scanResults.get(i);
3299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if ((mLastScanSettings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
33241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                mScanBuffer.add(new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
33341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                                scanResultsArray));
3349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mScanEventHandler != null) {
3379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if ((mLastScanSettings.reportEvents &
3389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                             WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0 ||
3399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                      (mLastScanSettings.reportEvents &
3409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                             WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0 ||
3419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                      (mLastScanSettings.reportEvents == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL
3429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                       && (mScanBuffer.size() >=
3439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                           (mScanBuffer.capacity() * mLastScanSettings.reportPercentThreshold
3449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            / 100) ||
3459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                           mScanBuffer.size() >= mLastScanSettings.reportNumScansThreshold)) ) {
3469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mScanEventHandler.onScanStatus();
3479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mHotlistHandler != null) {
3519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int event = mHotlistChangeBuffer.processScan(scanResultsArray);
3529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if ((event & ChangeBuffer.EVENT_FOUND) != 0) {
3539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mHotlistHandler.onHotlistApFound(
3549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_FOUND));
3559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if ((event & ChangeBuffer.EVENT_LOST) != 0) {
3579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mHotlistHandler.onHotlistApLost(
3589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_LOST));
3599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
3669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public WifiScanner.ScanData[] getLatestBatchedScanResults(boolean flush) {
36741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        synchronized(mSettingsLock) {
36841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            WifiScanner.ScanData[] results = mScanBuffer.get();
36941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            if (flush) {
37041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                mScanBuffer.clear();
37141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
37241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            return results;
3739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
3779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean setHotlist(WifiScanner.HotlistSettings settings,
3789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.HotlistEventHandler eventHandler) {
3799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings == null || eventHandler == null) {
3809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
3819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
3839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = eventHandler;
3849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.setSettings(settings.bssidInfos, settings.apLostThreshold, 1);
3859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
3869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
3909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void resetHotlist() {
3919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        synchronized(mSettingsLock) {
3929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.clearSettings();
3939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = null;
3949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class LastScanSettings {
3989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        int scanId;
3999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        long startTime;
4009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        int maxAps;
4019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        int reportEvents;
4029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        int reportNumScansThreshold;
4039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        int reportPercentThreshold;
4049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public LastScanSettings(int scanId, long startTime, int maxAps, int reportEvents,
4069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int reportNumScansThreshold, int reportPercentThreshold) {
4079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.scanId = scanId;
4089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.startTime = startTime;
4099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.maxAps = maxAps;
4109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportEvents = reportEvents;
4119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportNumScansThreshold = reportNumScansThreshold;
4129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportPercentThreshold = reportPercentThreshold;
4139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
4159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ScanBuffer {
4189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private final ArrayDeque<WifiScanner.ScanData> mBuffer;
4199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int capacity;
4209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanBuffer(int capacity) {
4229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer = new ArrayDeque<>(capacity);
4239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.capacity = capacity;
4249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int size() {
4279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.size();
4289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int capacity() {
4319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return capacity;
4329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public boolean isFull() {
4359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return size() == capacity;
4369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void add(WifiScanner.ScanData scanData) {
4399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (isFull()) {
4409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mBuffer.pollFirst();
4419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.offerLast(scanData);
4439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clear() {
4469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.clear();
4479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public WifiScanner.ScanData[] get() {
4509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.toArray(new WifiScanner.ScanData[mBuffer.size()]);
4519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
4539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ChangeBuffer {
4559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_NONE = 0;
4569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_LOST = 1;
4579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_FOUND = 2;
4589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private static int STATE_FOUND = 0;
4609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private WifiScanner.BssidInfo[] mBssidInfos = null;
4629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mApLostThreshold;
4639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mMinEvents;
4649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mLostCount = null;
4659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private ScanResult[] mMostRecentResult = null;
4669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mPendingEvent = null;
4679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private boolean mFiredEvents = false;
4689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private static ScanResult findResult(ScanResult[] results, String bssid) {
4709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < results.length; ++i) {
4719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (bssid.equalsIgnoreCase(results[i].BSSID)) {
4729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    return results[i];
4739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return null;
4769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void setSettings(WifiScanner.BssidInfo[] bssidInfos, int apLostThreshold,
4799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                int minEvents) {
4809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBssidInfos = bssidInfos;
4819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (apLostThreshold <= 0) {
4829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = 1;
4839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            else {
4859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = apLostThreshold;
4869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mMinEvents = minEvents;
4889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (bssidInfos != null) {
4899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = new int[bssidInfos.length];
4909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Arrays.fill(mLostCount, mApLostThreshold); // default to lost
4919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = new ScanResult[bssidInfos.length];
4929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = new int[bssidInfos.length];
4939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
4949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            else {
4969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = null;
4979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = null;
4989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = null;
4999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clearSettings() {
5039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            setSettings(null, 0, 0);
5049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
5079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Get the most recent scan results for APs that triggered the given event on the last call
5089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * to {@link #processScan}.
5099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
5109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanResult[] getLastResults(int event) {
5119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanResult> results = new ArrayList<>();
5129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
5139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] == event) {
5149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    results.add(mMostRecentResult[i]);
5159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return results.toArray(new ScanResult[results.size()]);
5189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
5219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Process the supplied scan results and determine if any events should be generated based
5229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * on the configured settings
5239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * @return The events that occurred
5249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
5259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int processScan(ScanResult[] scanResults) {
5269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mBssidInfos == null) {
5279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return EVENT_NONE;
5289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // clear events from last time
5319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mFiredEvents) {
5329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
5339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                for (int i = 0; i < mLostCount.length; ++i) {
5349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mPendingEvent[i] = EVENT_NONE;
5359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventCount = 0;
5399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventType = EVENT_NONE;
5409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
5419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = findResult(scanResults, mBssidInfos[i].bssid);
5429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int rssi = Integer.MIN_VALUE;
5439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (result != null) {
5449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mMostRecentResult[i] = result;
5459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    rssi = result.level;
5469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (rssi < mBssidInfos[i].low) {
5499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] < mApLostThreshold) {
5509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        mLostCount[i]++;
5519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mLostCount[i] >= mApLostThreshold) {
5539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            if (mPendingEvent[i] == EVENT_FOUND) {
5549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_NONE;
5559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
5569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            else {
5579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_LOST;
5589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
5599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
5609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
5619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                else {
5639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] >= mApLostThreshold) {
5649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mPendingEvent[i] == EVENT_LOST) {
5659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_NONE;
5669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
5679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        else {
5689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_FOUND;
5699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
5709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
5719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mLostCount[i] = STATE_FOUND;
5729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (DBG) {
5749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    Log.d(TAG, "ChangeBuffer BSSID: " + mBssidInfos[i].bssid + "=" + mLostCount[i] +
5759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            ", " + mPendingEvent[i] + ", rssi=" + rssi);
5769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] != EVENT_NONE) {
5789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    ++eventCount;
5799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    eventType |= mPendingEvent[i];
5809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (DBG) { Log.d(TAG, "ChangeBuffer events count=" + eventCount + ": " + eventType); }
5839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (eventCount >= mMinEvents) {
5849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = true;
5859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return eventType;
5869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return EVENT_NONE;
5889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
5909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills}
591