SupplicantWifiScannerImpl.java revision 2771787818003e53e8175036a3d09688c783f350
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 java.util.ArrayDeque;
309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.ArrayList;
319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Arrays;
329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Collections;
339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.HashSet;
349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.List;
359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Set;
369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
37f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills/**
385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills * Implementation of the WifiScanner HAL API that uses wpa_supplicant to perform all scans
39f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills * @see com.android.server.wifi.WifiScannerImpl for more details on each method
40f2f6f79242454ff9161f5af772292fa0180436f8Mitchell 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
605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mPendingBackgroundScanSettings = null;
615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mPendingBackgroundScanEventHandler = null;
625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mPendingSingleScanSettings = null;
635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mPendingSingleScanEventHandler = null;
645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    // Active background scan settings/state
665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mBackgroundScanSettings = null;
675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mBackgroundScanEventHandler = null;
685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private int mNextBackgroundScanPeriod = 0;
695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private int mNextBackgroundScanId = 0;
705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private boolean mBackgroundScanPeriodPending = false;
715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private boolean mBackgroundScanPaused = false;
725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private ScanBuffer mBackgroundScanBuffer = new ScanBuffer(SCAN_BUFFER_CAPACITY);
735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiScanner.ScanData mLatestSingleScanResult =
755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            new WifiScanner.ScanData(0, 0, new ScanResult[0]);
765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    // Settings for the currently running scan, null if no scan active
789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private LastScanSettings mLastScanSettings = null;
799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Active hotlist settings
819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.HotlistEventHandler mHotlistHandler = null;
829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private ChangeBuffer mHotlistChangeBuffer = new ChangeBuffer();
839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills    AlarmManager.OnAlarmListener mScanPeriodListener = new AlarmManager.OnAlarmListener() {
8541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            public void onAlarm() {
8641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                synchronized (mSettingsLock) {
8741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    handleScanPeriod();
8841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
8941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
9041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        };
9141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public SupplicantWifiScannerImpl(Context context, WifiNative wifiNative, Looper looper) {
939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mContext = context;
949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mWifiNative = wifiNative;
959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mEventHandler = new Handler(looper, this);
977d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills
987d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        // We can't enable these until WifiStateMachine switches to using WifiScanner because
997d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        //   WifiMonitor only supports sending results to one listener
1007d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        // TODO Enable these
1017d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        // Also need to fix tests again when this is enabled
1027d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        // WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
1037d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        //         WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
1047d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        // WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
1057d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        //         WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
1069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
1109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_cache_size = Integer.MAX_VALUE;
1119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_buckets = MAX_SCAN_BUCKETS;
1129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_ap_cache_per_scan = MAX_APS_PER_SCAN;
1139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_rssi_sample_size = 8;
1149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_reporting_threshold = SCAN_BUFFER_CAPACITY;
1159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_hotlist_bssids = 0;
1169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_significant_wifi_change_aps = 0;
1177d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        // TODO reenable once scan results handlers are enabled again
1187d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        return false;
1199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
122f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    public boolean startSingleScan(WifiNative.ScanSettings settings,
123f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills            WifiNative.ScanEventHandler eventHandler) {
1245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (eventHandler == null || settings == null) {
1255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings
1265fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + ",eventHandler=" + eventHandler);
1275fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return false;
1285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (mPendingSingleScanSettings != null
1305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
1315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "A single scan is already running");
1325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return false;
1335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
1355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingSingleScanSettings = settings;
1365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingSingleScanEventHandler = eventHandler;
1375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            processPendingScans();
1385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return true;
1395fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
140f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    }
141f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills
142f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    @Override
143f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    public WifiScanner.ScanData getLatestSingleScanResults() {
1445fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        return mLatestSingleScanResult;
145f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    }
146f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills
147f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    @Override
1489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean startBatchedScan(WifiNative.ScanSettings settings,
1499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.ScanEventHandler eventHandler) {
1505fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings == null || eventHandler == null) {
1515fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "Invalid arguments for startBatched: settings=" + settings
1525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + ",eventHandler=" + eventHandler);
1539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1565fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.max_ap_per_scan < 0 || settings.max_ap_per_scan > MAX_APS_PER_SCAN) {
1579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1595fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.num_buckets < 0 || settings.num_buckets > MAX_SCAN_BUCKETS) {
1609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.report_threshold_num_scans < 0
1635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                || settings.report_threshold_num_scans > SCAN_BUFFER_CAPACITY) {
1649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.report_threshold_percent < 0 || settings.report_threshold_percent > 100) {
1679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.base_period_ms <= 0) {
1709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        for (int i = 0; i < settings.num_buckets; ++i) {
1739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.BucketSettings bucket = settings.buckets[i];
1745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (bucket.period_ms % settings.base_period_ms != 0) {
1759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return false;
1765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
1779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
1789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
1809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            stopBatchedScan();
1815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.d(TAG, "Starting scan num_buckets=" + settings.num_buckets + ", base_period="
1825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + settings.base_period_ms + " ms");
1835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanSettings = settings;
1845fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanEventHandler = eventHandler;
1859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod(); // Try to start scan immediately
1869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
1879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
1889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void stopBatchedScan() {
1925fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
1935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Stopping scan");
1945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanSettings = null;
1955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanEventHandler = null;
1965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanSettings = null;
1975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanEventHandler = null;
1985fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = false;
1995fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = false;
2009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
2019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void pauseBatchedScan() {
2065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Pausing scan");
2089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // if there isn't a pending scan then make the current scan pending
2095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanSettings == null) {
2105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanSettings = mBackgroundScanSettings;
2115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler = mBackgroundScanEventHandler;
2129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
2135fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanSettings = null;
2145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanEventHandler = null;
2155fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = false;
2165fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = true;
2179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
2199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiScanner.ScanData[] results = getLatestBatchedScanResults(/* flush = */ true);
2215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanEventHandler != null) {
2225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler.onScanPaused(results);
2235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
2249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void restartBatchedScan() {
2295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Restarting scan");
2315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanEventHandler != null) {
2325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler.onScanRestarted();
2335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
2345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = false;
2359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod();
2369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void unscheduleScansLocked() {
24041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        mAlarmManager.cancel(mScanPeriodListener);
2419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mLastScanSettings = null; // make sure that a running scan is marked as ended
2429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void handleScanPeriod() {
2455fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2465fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = true;
2475fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            processPendingScans();
2485fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2495fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    }
2505fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
2515fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private void processPendingScans() {
2525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mLastScanSettings != null) {
2549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
2559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
2569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Set<Integer> freqs = new HashSet<>();
2585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            LastScanSettings newScanSettings = new LastScanSettings(SystemClock.elapsedRealtime());
2599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            // Update scan settings if there is a pending scan
2615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (!mBackgroundScanPaused) {
2625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mPendingBackgroundScanSettings != null) {
2635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanSettings = mPendingBackgroundScanSettings;
2645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanEventHandler = mPendingBackgroundScanEventHandler;
2655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mNextBackgroundScanPeriod = 0;
2665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mPendingBackgroundScanSettings = null;
2675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mPendingBackgroundScanEventHandler = null;
2685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanPeriodPending = true;
2695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
2705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanPeriodPending) {
2715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mBackgroundScanSettings != null) {
2725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        int reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; // default to no batch
2735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        boolean haveBackgroundScanChannels = false;
2745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        for (int bucket_id = 0; bucket_id < mBackgroundScanSettings.num_buckets;
2755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                ++bucket_id) {
2765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            WifiNative.BucketSettings bucket =
2775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.buckets[bucket_id];
2785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            if (mNextBackgroundScanPeriod % (bucket.period_ms
2795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            / mBackgroundScanSettings.base_period_ms) == 0) {
2805fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                if ((bucket.report_events
2815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) {
2825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    reportEvents |= WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
2835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                }
2845fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                if ((bucket.report_events
2855fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
2865fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
2875fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                }
2885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                // only no batch if all buckets specify it
2895fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                if ((bucket.report_events
2905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
2915fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    reportEvents &= ~WifiScanner.REPORT_EVENT_NO_BATCH;
2925fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                }
2935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
2945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                if (bucket.band != WifiScanner.WIFI_BAND_UNSPECIFIED) {
2955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    WifiScanner.ChannelSpec[] channels =
2965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            WifiChannelHelper.getChannelsForBand(bucket.band);
2975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    for (WifiScanner.ChannelSpec channel : channels) {
2985fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                        freqs.add(channel.frequency);
2995fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                        haveBackgroundScanChannels = true;
3005fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    }
3015fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                } else {
3025fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    for (int channel_id = 0; channel_id < bucket.num_channels;
3035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            ++channel_id) {
3045fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                        WifiNative.ChannelSettings channel =
3055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                bucket.channels[channel_id];
3065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                        freqs.add(channel.frequency);
3075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                        haveBackgroundScanChannels = true;
3085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    }
3095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                }
3109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
3119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
3125fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        if (haveBackgroundScanChannels) {
3135fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            newScanSettings.setBackgroundScan(mNextBackgroundScanId++,
3145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.max_ap_per_scan, reportEvents,
3155fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.report_threshold_num_scans,
3165fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.report_threshold_percent);
3179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
3189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
3195fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
3205fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mNextBackgroundScanPeriod++;
3215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanPeriodPending = false;
3225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mAlarmManager.set(AlarmManager.RTC_WAKEUP,
3235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            System.currentTimeMillis() + mBackgroundScanSettings.base_period_ms,
3245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            "SupplicantWifiScannerImpl Period",
3255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            mScanPeriodListener, mEventHandler);
3269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3275fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
3285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
3295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingSingleScanSettings != null) {
3305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                boolean reportFullResults = false;
3315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                Set<Integer> singleScanFreqs = new HashSet<>();
3325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                for (int i = 0; i < mPendingSingleScanSettings.num_buckets; ++i) {
3335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    WifiNative.BucketSettings bucketSettings =
3345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            mPendingSingleScanSettings.buckets[i];
3355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((bucketSettings.report_events
3365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
3375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        reportFullResults = true;
3389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
3395fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
3405fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        for (int j = 0; j < bucketSettings.num_channels; ++j) {
3415fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            WifiNative.ChannelSettings channel = bucketSettings.channels[j];
3425fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            singleScanFreqs.add(channel.frequency);
3435fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        }
3445fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    } else {
3455fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        WifiScanner.ChannelSpec[] channels =
3465fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                WifiChannelHelper.getChannelsForBand(bucketSettings.band);
3475fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        for (WifiScanner.ChannelSpec channel : channels) {
3485fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            singleScanFreqs.add(channel.frequency);
3495fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        }
3509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
3519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                freqs.addAll(singleScanFreqs);
3535fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                newScanSettings.setSingleScan(reportFullResults, singleScanFreqs,
3545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mPendingSingleScanEventHandler);
3559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3565fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingSingleScanSettings = null;
3575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingSingleScanEventHandler = null;
3585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
3595fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
3605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (freqs.size() > 0) {
3615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                boolean success = mWifiNative.scan(
3625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, freqs);
3635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (success) {
3645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    // TODO handle scan timeout
3655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    Log.d(TAG, "Starting wifi scan for " + freqs.size() + " freqs"
3665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            + ", background=" + newScanSettings.backgroundScanActive
3675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            + ", single=" + newScanSettings.singleScanActive);
3685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mLastScanSettings = newScanSettings;
3695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
3705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    Log.w(TAG, "Failed starting wifi scan for " + freqs.size() + " freqs");
3715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    // TODO indicate failure for single and background scans
3725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
3739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
3789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean handleMessage(Message msg) {
3799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        switch(msg.what) {
3809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_FAILED_EVENT:
381f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills                // TODO indicate failure to caller
3829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Log.w(TAG, "Scan failed");
3839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                synchronized (mSettingsLock) {
3849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mLastScanSettings = null;
3859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3865fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                processPendingScans();
3879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
3889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_RESULTS_EVENT:
3899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                pollLatestScanData();
3905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                processPendingScans();
3919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
3929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            default:
3939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                // ignore unknown event
3949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        return true;
3969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void pollLatestScanData() {
3995fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
4005fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings == null) {
4019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                 // got a scan before we started scanning or after scan was canceled
4029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
4039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId);
4069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanDetail> nativeResults = mWifiNative.getScanResults();
4075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            List<ScanResult> singleScanResults = new ArrayList<>();
4085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            List<ScanResult> backgroundScanResults = new ArrayList<>();
4099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < nativeResults.size(); ++i) {
4109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = nativeResults.get(i).getScanResult();
4119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                long timestamp_ms = result.timestamp / 1000; // convert us -> ms
4129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (timestamp_ms > mLastScanSettings.startTime) {
4135fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mLastScanSettings.backgroundScanActive) {
4145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        backgroundScanResults.add(result);
4155fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
4165fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mLastScanSettings.singleScanActive
4175fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            && mLastScanSettings.singleScanFreqs.contains(result.frequency)) {
4185fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        singleScanResults.add(result);
4195fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
4205fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
4219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    // was a cached result in wpa_supplicant
4229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
42441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
4255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings.backgroundScanActive) {
4265fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanEventHandler != null) {
4275fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((mLastScanSettings.reportEvents
4285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
4295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        for (ScanResult scanResult : backgroundScanResults) {
4305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            mBackgroundScanEventHandler.onFullScanResult(scanResult);
4315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        }
43241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    }
43341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
43441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
4352771787818003e53e8175036a3d09688c783f350Mitchell Wills                Collections.sort(backgroundScanResults, SCAN_RESULT_SORT_COMPARATOR);
4365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                ScanResult[] scanResultsArray = new ScanResult[Math.min(mLastScanSettings.maxAps,
4375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            backgroundScanResults.size())];
4385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                for (int i = 0; i < scanResultsArray.length; ++i) {
4395fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    scanResultsArray[i] = backgroundScanResults.get(i);
4405fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
4419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4425fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if ((mLastScanSettings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
4435fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanBuffer.add(new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
4445fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    scanResultsArray));
4455fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
4469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4475fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanEventHandler != null) {
4485fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((mLastScanSettings.reportEvents
4495fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0
4505fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            || (mLastScanSettings.reportEvents
4515fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0
4525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            || (mLastScanSettings.reportEvents
4535fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL
4545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    && (mBackgroundScanBuffer.size()
4555fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            >= (mBackgroundScanBuffer.capacity()
4565fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                    * mLastScanSettings.reportPercentThreshold
4575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                    / 100)
4585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            || mBackgroundScanBuffer.size()
4595fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            >= mLastScanSettings.reportNumScansThreshold))) {
4605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mBackgroundScanEventHandler.onScanStatus();
4615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
4629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mHotlistHandler != null) {
4655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    int event = mHotlistChangeBuffer.processScan(backgroundScanResults);
4665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((event & ChangeBuffer.EVENT_FOUND) != 0) {
4675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mHotlistHandler.onHotlistApFound(
4685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_FOUND));
4695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
4705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((event & ChangeBuffer.EVENT_LOST) != 0) {
4715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mHotlistHandler.onHotlistApLost(
4725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_LOST));
4735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
4749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
4765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
4775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings.singleScanActive
4785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    && mLastScanSettings.singleScanEventHandler != null) {
4795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mLastScanSettings.reportSingleScanFullResults) {
4805fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    for (ScanResult scanResult : singleScanResults) {
4815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult);
4825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
4839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4842771787818003e53e8175036a3d09688c783f350Mitchell Wills                Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
4855fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mLatestSingleScanResult = new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
4865fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
4875fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mLastScanSettings.singleScanEventHandler.onScanResultsAvailable();
4889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4895fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
4905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mLastScanSettings = null;
4919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
4939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
4969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public WifiScanner.ScanData[] getLatestBatchedScanResults(boolean flush) {
4975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
4985fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            WifiScanner.ScanData[] results = mBackgroundScanBuffer.get();
49941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            if (flush) {
5005fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mBackgroundScanBuffer.clear();
50141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
50241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            return results;
5039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
5059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
5079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean setHotlist(WifiScanner.HotlistSettings settings,
5089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.HotlistEventHandler eventHandler) {
5099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings == null || eventHandler == null) {
5109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
5119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5125fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
5139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = eventHandler;
5149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.setSettings(settings.bssidInfos, settings.apLostThreshold, 1);
5159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
5169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
5189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
5209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void resetHotlist() {
5215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
5229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.clearSettings();
5239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = null;
5249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
5269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class LastScanSettings {
5285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public long startTime;
5295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
5305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public LastScanSettings(long startTime) {
5315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.startTime = startTime;
5325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
5335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
5345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        // Background settings
5355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean backgroundScanActive = false;
5365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int scanId;
5375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int maxAps;
5385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportEvents;
5395fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportNumScansThreshold;
5405fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportPercentThreshold;
5415fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
5425fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public void setBackgroundScan(int scanId, int maxAps, int reportEvents,
5439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int reportNumScansThreshold, int reportPercentThreshold) {
5445fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.backgroundScanActive = true;
5459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.scanId = scanId;
5469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.startTime = startTime;
5479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.maxAps = maxAps;
5489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportEvents = reportEvents;
5499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportNumScansThreshold = reportNumScansThreshold;
5509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportPercentThreshold = reportPercentThreshold;
5519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
5535fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        // Single scan settings
5545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean singleScanActive = false;
5555fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean reportSingleScanFullResults;
5565fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public Set<Integer> singleScanFreqs;
5575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public WifiNative.ScanEventHandler singleScanEventHandler;
5585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
5595fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public void setSingleScan(boolean reportSingleScanFullResults,
5605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                Set<Integer> singleScanFreqs, WifiNative.ScanEventHandler singleScanEventHandler) {
5615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            singleScanActive = true;
5625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.reportSingleScanFullResults = reportSingleScanFullResults;
5635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.singleScanFreqs = singleScanFreqs;
5645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.singleScanEventHandler = singleScanEventHandler;
5655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
5669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
5679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ScanBuffer {
5709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private final ArrayDeque<WifiScanner.ScanData> mBuffer;
5715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        private int mCapacity;
5729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanBuffer(int capacity) {
5745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mCapacity = capacity;
5755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBuffer = new ArrayDeque<>(mCapacity);
5769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int size() {
5799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.size();
5809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int capacity() {
5835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return mCapacity;
5849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public boolean isFull() {
5875fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return size() == mCapacity;
5889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void add(WifiScanner.ScanData scanData) {
5919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (isFull()) {
5929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mBuffer.pollFirst();
5939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.offerLast(scanData);
5959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clear() {
5989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.clear();
5999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public WifiScanner.ScanData[] get() {
6029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.toArray(new WifiScanner.ScanData[mBuffer.size()]);
6039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
6059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ChangeBuffer {
6079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_NONE = 0;
6089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_LOST = 1;
6099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_FOUND = 2;
6109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public static int STATE_FOUND = 0;
6129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private WifiScanner.BssidInfo[] mBssidInfos = null;
6149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mApLostThreshold;
6159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mMinEvents;
6169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mLostCount = null;
6179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private ScanResult[] mMostRecentResult = null;
6189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mPendingEvent = null;
6199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private boolean mFiredEvents = false;
6209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        private static ScanResult findResult(List<ScanResult> results, String bssid) {
6225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            for (int i = 0; i < results.size(); ++i) {
6235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (bssid.equalsIgnoreCase(results.get(i).BSSID)) {
6245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    return results.get(i);
6259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
6269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
6279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return null;
6289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void setSettings(WifiScanner.BssidInfo[] bssidInfos, int apLostThreshold,
6319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                int minEvents) {
6329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBssidInfos = bssidInfos;
6339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (apLostThreshold <= 0) {
6349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = 1;
6355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            } else {
6369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = apLostThreshold;
6379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
6389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mMinEvents = minEvents;
6399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (bssidInfos != null) {
6409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = new int[bssidInfos.length];
6419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Arrays.fill(mLostCount, mApLostThreshold); // default to lost
6429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = new ScanResult[bssidInfos.length];
6439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = new int[bssidInfos.length];
6449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
6455fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            } else {
6469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = null;
6479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = null;
6489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = null;
6499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
6509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clearSettings() {
6539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            setSettings(null, 0, 0);
6549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
6579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Get the most recent scan results for APs that triggered the given event on the last call
6589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * to {@link #processScan}.
6599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
6609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanResult[] getLastResults(int event) {
6619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanResult> results = new ArrayList<>();
6629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
6639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] == event) {
6649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    results.add(mMostRecentResult[i]);
6659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
6669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
6679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return results.toArray(new ScanResult[results.size()]);
6689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
6719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Process the supplied scan results and determine if any events should be generated based
6729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * on the configured settings
6739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * @return The events that occurred
6749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
6755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int processScan(List<ScanResult> scanResults) {
6769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mBssidInfos == null) {
6779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return EVENT_NONE;
6789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
6799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // clear events from last time
6819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mFiredEvents) {
6829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
6839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                for (int i = 0; i < mLostCount.length; ++i) {
6849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mPendingEvent[i] = EVENT_NONE;
6859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
6869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
6879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventCount = 0;
6899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventType = EVENT_NONE;
6909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
6919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = findResult(scanResults, mBssidInfos[i].bssid);
6929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int rssi = Integer.MIN_VALUE;
6939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (result != null) {
6949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mMostRecentResult[i] = result;
6959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    rssi = result.level;
6969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
6979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (rssi < mBssidInfos[i].low) {
6999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] < mApLostThreshold) {
7009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        mLostCount[i]++;
7019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
7029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mLostCount[i] >= mApLostThreshold) {
7039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            if (mPendingEvent[i] == EVENT_FOUND) {
7049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_NONE;
7055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            } else {
7069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_LOST;
7079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
7089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
7099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
7105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
7119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] >= mApLostThreshold) {
7129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mPendingEvent[i] == EVENT_LOST) {
7139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_NONE;
7145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        } else {
7159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_FOUND;
7169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
7179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
7189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mLostCount[i] = STATE_FOUND;
7199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
7209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (DBG) {
7215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    Log.d(TAG, "ChangeBuffer BSSID: " + mBssidInfos[i].bssid + "=" + mLostCount[i]
7225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            + ", " + mPendingEvent[i] + ", rssi=" + rssi);
7239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
7249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] != EVENT_NONE) {
7259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    ++eventCount;
7269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    eventType |= mPendingEvent[i];
7279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
7289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
7295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "ChangeBuffer events count=" + eventCount + ": " + eventType);
7309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (eventCount >= mMinEvents) {
7319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = true;
7329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return eventType;
7339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
7349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return EVENT_NONE;
7359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
7379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills}
738