SupplicantWifiScannerImpl.java revision dcd877d6c143db557884993ea437e2a432cb0ba3
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;
229153bd67d51b305ffdd61355e0748e3c332c2cafRoshan Piusimport android.net.wifi.WifiConfiguration;
239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.net.wifi.WifiScanner;
249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.Handler;
259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.Looper;
269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.Message;
279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.os.SystemClock;
289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport android.util.Log;
299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Piusimport com.android.internal.R;
317e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Willsimport com.android.server.wifi.scanner.ChannelHelper;
327e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Willsimport com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
337e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Willsimport com.android.server.wifi.scanner.NoBandChannelHelper;
347e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills
359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.ArrayDeque;
369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.ArrayList;
379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Arrays;
389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Collections;
39d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Piusimport java.util.HashSet;
409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.List;
419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Set;
429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
43f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills/**
445fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills * Implementation of the WifiScanner HAL API that uses wpa_supplicant to perform all scans
45f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills * @see com.android.server.wifi.WifiScannerImpl for more details on each method
46f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills */
479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willspublic class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handler.Callback {
489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final String TAG = "SupplicantWifiScannerImpl";
499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final boolean DBG = false;
509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int SCAN_BUFFER_CAPACITY = 10;
529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int MAX_APS_PER_SCAN = 32;
539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int MAX_SCAN_BUCKETS = 16;
549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final String ACTION_SCAN_PERIOD =
569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            "com.android.server.util.SupplicantWifiScannerImpl.action.SCAN_PERIOD";
579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final Context mContext;
599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final WifiNative mWifiNative;
609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final AlarmManager mAlarmManager;
619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final Handler mEventHandler;
627e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    private final ChannelHelper mChannelHelper;
639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private Object mSettingsLock = new Object();
659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Next scan settings to apply when the previous scan completes
675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mPendingBackgroundScanSettings = null;
685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mPendingBackgroundScanEventHandler = null;
695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mPendingSingleScanSettings = null;
705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mPendingSingleScanEventHandler = null;
715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    // Active background scan settings/state
735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mBackgroundScanSettings = null;
745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mBackgroundScanEventHandler = null;
755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private int mNextBackgroundScanPeriod = 0;
765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private int mNextBackgroundScanId = 0;
775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private boolean mBackgroundScanPeriodPending = false;
785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private boolean mBackgroundScanPaused = false;
795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private ScanBuffer mBackgroundScanBuffer = new ScanBuffer(SCAN_BUFFER_CAPACITY);
805fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiScanner.ScanData mLatestSingleScanResult =
825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            new WifiScanner.ScanData(0, 0, new ScanResult[0]);
835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
845fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    // Settings for the currently running scan, null if no scan active
859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private LastScanSettings mLastScanSettings = null;
869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Active hotlist settings
889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.HotlistEventHandler mHotlistHandler = null;
899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private ChangeBuffer mHotlistChangeBuffer = new ChangeBuffer();
909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
919153bd67d51b305ffdd61355e0748e3c332c2cafRoshan Pius    // Pno related info.
92063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius    private WifiNative.PnoSettings mPnoSettings = null;
939153bd67d51b305ffdd61355e0748e3c332c2cafRoshan Pius    private WifiNative.PnoEventHandler mPnoEventHandler;
9462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private boolean mHwPnoRunning = false;
9562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private final boolean mHwPnoScanSupported;
969153bd67d51b305ffdd61355e0748e3c332c2cafRoshan Pius
9741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills    AlarmManager.OnAlarmListener mScanPeriodListener = new AlarmManager.OnAlarmListener() {
9841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            public void onAlarm() {
9941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                synchronized (mSettingsLock) {
10041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    handleScanPeriod();
10141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
10241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
10341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        };
10441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
1052332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    public SupplicantWifiScannerImpl(Context context, WifiNative wifiNative,
1062332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            ChannelHelper channelHelper, Looper looper) {
1079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mContext = context;
1089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mWifiNative = wifiNative;
1092332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        mChannelHelper = channelHelper;
1109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
1119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mEventHandler = new Handler(looper, this);
1127d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills
11362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        // Check if the device supports HW PNO scans.
11462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        mHwPnoScanSupported = mContext.getResources().getBoolean(
11562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                R.bool.config_wifi_background_scan_support);
11662bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius
1178adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills        WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
1188adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills                WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
1198adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills        WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
1208adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills                WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
1219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1232332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    public SupplicantWifiScannerImpl(Context context, WifiNative wifiNative, Looper looper) {
1242332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        // TODO figure out how to get channel information from supplicant
1252332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        this(context, wifiNative, new NoBandChannelHelper(), looper);
1262332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
1272332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
1289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1291e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills    public void cleanup() {
1301e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        synchronized (mSettingsLock) {
1311e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mPendingSingleScanSettings = null;
1321e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mPendingSingleScanEventHandler = null;
13362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            stopHwPnoScan();
1341e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            stopBatchedScan();
1351e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            resetHotlist();
1361e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            untrackSignificantWifiChange();
1371e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mLastScanSettings = null; // finally clear any active scan
1382332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            // TODO(b/27677054): Remove this once all PNO scans are started via Scanner
1392332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mWifiNative.resumeBackgroundScan();
1401e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        }
1411e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills    }
1421e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills
1431e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills    @Override
1449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
1459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_cache_size = Integer.MAX_VALUE;
1469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_buckets = MAX_SCAN_BUCKETS;
1479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_ap_cache_per_scan = MAX_APS_PER_SCAN;
1489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_rssi_sample_size = 8;
1499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_reporting_threshold = SCAN_BUFFER_CAPACITY;
1509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_hotlist_bssids = 0;
1519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_significant_wifi_change_aps = 0;
1527d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        // TODO reenable once scan results handlers are enabled again
1537d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills        return false;
1549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1577e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    public ChannelHelper getChannelHelper() {
1587e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills        return mChannelHelper;
1597e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    }
1607e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills
1617e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    @Override
162f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    public boolean startSingleScan(WifiNative.ScanSettings settings,
163f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills            WifiNative.ScanEventHandler eventHandler) {
1645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (eventHandler == null || settings == null) {
1655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings
1665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + ",eventHandler=" + eventHandler);
1675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return false;
1685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (mPendingSingleScanSettings != null
1705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
1715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "A single scan is already running");
1725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return false;
1735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
1755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingSingleScanSettings = settings;
1765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingSingleScanEventHandler = eventHandler;
1775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            processPendingScans();
1785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return true;
1795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
180f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    }
181f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills
182f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    @Override
183f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    public WifiScanner.ScanData getLatestSingleScanResults() {
1845fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        return mLatestSingleScanResult;
185f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    }
186f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills
187f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    @Override
1889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean startBatchedScan(WifiNative.ScanSettings settings,
1899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.ScanEventHandler eventHandler) {
1905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings == null || eventHandler == null) {
1915fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "Invalid arguments for startBatched: settings=" + settings
1925fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + ",eventHandler=" + eventHandler);
1939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.max_ap_per_scan < 0 || settings.max_ap_per_scan > MAX_APS_PER_SCAN) {
1979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
1985fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1995fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.num_buckets < 0 || settings.num_buckets > MAX_SCAN_BUCKETS) {
2009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2015fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2025fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.report_threshold_num_scans < 0
2035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                || settings.report_threshold_num_scans > SCAN_BUFFER_CAPACITY) {
2049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.report_threshold_percent < 0 || settings.report_threshold_percent > 100) {
2079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.base_period_ms <= 0) {
2109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        for (int i = 0; i < settings.num_buckets; ++i) {
2139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.BucketSettings bucket = settings.buckets[i];
2145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (bucket.period_ms % settings.base_period_ms != 0) {
2159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return false;
2165fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
2179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2195fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            stopBatchedScan();
2215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.d(TAG, "Starting scan num_buckets=" + settings.num_buckets + ", base_period="
2225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + settings.base_period_ms + " ms");
2235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanSettings = settings;
2245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanEventHandler = eventHandler;
2259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod(); // Try to start scan immediately
2269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
2279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void stopBatchedScan() {
2325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Stopping scan");
2345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanSettings = null;
2355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanEventHandler = null;
2365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanSettings = null;
2375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanEventHandler = null;
2385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = false;
2395fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = false;
2409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
2419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2421e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        processPendingScans();
2439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void pauseBatchedScan() {
2475fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2485fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Pausing scan");
2499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // if there isn't a pending scan then make the current scan pending
2505fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanSettings == null) {
2515fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanSettings = mBackgroundScanSettings;
2525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler = mBackgroundScanEventHandler;
2539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
2545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanSettings = null;
2555fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanEventHandler = null;
2565fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = false;
2575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = true;
2589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
2609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiScanner.ScanData[] results = getLatestBatchedScanResults(/* flush = */ true);
2625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanEventHandler != null) {
2635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler.onScanPaused(results);
2645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
2659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2661e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        processPendingScans();
2679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void restartBatchedScan() {
2715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Restarting scan");
2735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanEventHandler != null) {
2745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler.onScanRestarted();
2755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
2765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = false;
2779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod();
2789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void unscheduleScansLocked() {
28241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        mAlarmManager.cancel(mScanPeriodListener);
2831e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        if (mLastScanSettings != null) {
2841e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mLastScanSettings.backgroundScanActive = false;
2851e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        }
2869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void handleScanPeriod() {
2895fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = true;
2915fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            processPendingScans();
2925fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    }
2945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
2955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private void processPendingScans() {
2965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
29762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            // Wait for the active scan result to come back to reschedule other scans,
29862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            // unless if HW pno scan is running. Hw PNO scans are paused it if there
29962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            // are other pending scans,
30062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if (mLastScanSettings != null && !mLastScanSettings.hwPnoScanActive) {
3019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
3029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3047e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills            ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
305d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius            Set<Integer> hiddenNetworkIdSet = new HashSet<Integer>();
30663539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills            final LastScanSettings newScanSettings =
30763539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    new LastScanSettings(SystemClock.elapsedRealtime());
3089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            // Update scan settings if there is a pending scan
3105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (!mBackgroundScanPaused) {
3115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mPendingBackgroundScanSettings != null) {
3125fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanSettings = mPendingBackgroundScanSettings;
3135fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanEventHandler = mPendingBackgroundScanEventHandler;
3145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mNextBackgroundScanPeriod = 0;
3155fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mPendingBackgroundScanSettings = null;
3165fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mPendingBackgroundScanEventHandler = null;
3175fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanPeriodPending = true;
3185fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
3195fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanPeriodPending) {
3205fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mBackgroundScanSettings != null) {
3215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        int reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; // default to no batch
3225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        for (int bucket_id = 0; bucket_id < mBackgroundScanSettings.num_buckets;
3235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                ++bucket_id) {
3245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            WifiNative.BucketSettings bucket =
3255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.buckets[bucket_id];
3265fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            if (mNextBackgroundScanPeriod % (bucket.period_ms
3275fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            / mBackgroundScanSettings.base_period_ms) == 0) {
3285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                if ((bucket.report_events
3295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) {
3305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    reportEvents |= WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
3315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                }
3325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                if ((bucket.report_events
3335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
3345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
3355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                }
3365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                // only no batch if all buckets specify it
3375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                if ((bucket.report_events
3385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
3395fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    reportEvents &= ~WifiScanner.REPORT_EVENT_NO_BATCH;
3405fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                }
3415fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
3427e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                                allFreqs.addChannels(bucket);
3439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
3449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
3457e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                        if (!allFreqs.isEmpty()) {
3465fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            newScanSettings.setBackgroundScan(mNextBackgroundScanId++,
3475fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.max_ap_per_scan, reportEvents,
3485fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.report_threshold_num_scans,
3495fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    mBackgroundScanSettings.report_threshold_percent);
35062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                            // When PNO scan is enabled and HW does not support PNO scans,
35162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                            // tag SwPno as enabled for each background scan
352dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius                            if (isSwPnoScanRequired()) {
35362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                                newScanSettings.setSwPnoScan(mPnoEventHandler);
35462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                            }
3559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
35662bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius
357d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                        int[] hiddenNetworkIds = mBackgroundScanSettings.hiddenNetworkIds;
358d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                        if (hiddenNetworkIds != null) {
359d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                            for (int i = 0; i < hiddenNetworkIds.length; i++) {
360d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                                hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
361d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                            }
362d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                        }
3639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
3645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
3655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mNextBackgroundScanPeriod++;
3665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanPeriodPending = false;
3675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mAlarmManager.set(AlarmManager.RTC_WAKEUP,
3685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            System.currentTimeMillis() + mBackgroundScanSettings.base_period_ms,
3695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            "SupplicantWifiScannerImpl Period",
3705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            mScanPeriodListener, mEventHandler);
3719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
3735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
3745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingSingleScanSettings != null) {
3755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                boolean reportFullResults = false;
3767e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                ChannelCollection singleScanFreqs = mChannelHelper.createChannelCollection();
3775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                for (int i = 0; i < mPendingSingleScanSettings.num_buckets; ++i) {
3785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    WifiNative.BucketSettings bucketSettings =
3795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            mPendingSingleScanSettings.buckets[i];
3805fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((bucketSettings.report_events
3815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
3825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        reportFullResults = true;
3839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
3847e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                    singleScanFreqs.addChannels(bucketSettings);
3857e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                    allFreqs.addChannels(bucketSettings);
3869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
3875fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                newScanSettings.setSingleScan(reportFullResults, singleScanFreqs,
3885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mPendingSingleScanEventHandler);
389d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                int[] hiddenNetworkIds = mPendingSingleScanSettings.hiddenNetworkIds;
390d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                if (hiddenNetworkIds != null) {
391d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                    for (int i = 0; i < hiddenNetworkIds.length; i++) {
392d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                        hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
393d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                    }
394d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                }
3955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingSingleScanSettings = null;
3965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingSingleScanEventHandler = null;
3975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
3985fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
39962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if ((newScanSettings.backgroundScanActive || newScanSettings.singleScanActive)
40062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                    && !allFreqs.isEmpty()) {
40162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                pauseHwPnoScan();
4022332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                // TODO(b/27677054): Remove this once all PNO scans are started via Scanner
4032332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                mWifiNative.pauseBackgroundScan();
4047e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                Set<Integer> freqs = allFreqs.getSupplicantScanFreqs();
405d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                boolean success = mWifiNative.scan(freqs, hiddenNetworkIdSet);
4065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (success) {
4075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    // TODO handle scan timeout
40863539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    Log.d(TAG, "Starting wifi scan for freqs=" + freqs
4095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            + ", background=" + newScanSettings.backgroundScanActive
4105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            + ", single=" + newScanSettings.singleScanActive);
4115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mLastScanSettings = newScanSettings;
4125fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
41363539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    Log.e(TAG, "Failed to start scan, freqs=" + freqs);
41463539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    // indicate scan failure async
41563539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    mEventHandler.post(new Runnable() {
41663539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                            public void run() {
41763539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                newScanSettings.singleScanActive = false;
41863539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                if (newScanSettings.singleScanEventHandler != null) {
41963539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                    newScanSettings.singleScanEventHandler
42063539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                            .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
42163539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                }
42263539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                            }
42363539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                        });
42463539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    // TODO if scans fail enough background scans should be failed as well
4255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
426dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius            } else if (isHwPnoScanRequired()) {
42762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                newScanSettings.setHwPnoScan(mPnoEventHandler);
42862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                boolean success = resumeHwPnoScan();
429063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                if (success) {
430063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    Log.d(TAG, "Starting wifi PNO scan");
431063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    mLastScanSettings = newScanSettings;
432063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                } else {
433063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    Log.e(TAG, "Failed to start PNO scan");
434063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    // indicate scan failure async
435063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    mEventHandler.post(new Runnable() {
436063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                        public void run() {
437063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            if (mPnoEventHandler != null) {
438063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                                mPnoEventHandler.onPnoScanFailed();
439063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            }
440063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            // Clean up PNO state, we don't want to continue PNO scanning.
441063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            mPnoSettings = null;
442063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            mPnoEventHandler = null;
443063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                        }
444063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    });
445063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                }
4462332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            } else {
4472332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                // TODO(b/27677054): Remove this once all PNO scans are started via Scanner
4482332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                mWifiNative.resumeBackgroundScan();
4499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
4529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
4549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean handleMessage(Message msg) {
4559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        switch(msg.what) {
4569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_FAILED_EVENT:
457f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills                // TODO indicate failure to caller
4589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Log.w(TAG, "Scan failed");
4599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                synchronized (mSettingsLock) {
4609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mLastScanSettings = null;
4619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                processPendingScans();
4639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
4649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_RESULTS_EVENT:
4659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                pollLatestScanData();
4665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                processPendingScans();
4679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
4689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            default:
4699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                // ignore unknown event
4709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        return true;
4729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
4739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void pollLatestScanData() {
4755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
4765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings == null) {
4779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                 // got a scan before we started scanning or after scan was canceled
4789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
4799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId);
4829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanDetail> nativeResults = mWifiNative.getScanResults();
4835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            List<ScanResult> singleScanResults = new ArrayList<>();
4845fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            List<ScanResult> backgroundScanResults = new ArrayList<>();
48562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            List<ScanResult> hwPnoScanResults = new ArrayList<>();
4869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < nativeResults.size(); ++i) {
4879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = nativeResults.get(i).getScanResult();
4889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                long timestamp_ms = result.timestamp / 1000; // convert us -> ms
4899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (timestamp_ms > mLastScanSettings.startTime) {
4905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mLastScanSettings.backgroundScanActive) {
4915fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        backgroundScanResults.add(result);
4925fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
4935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mLastScanSettings.singleScanActive
4947e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                            && mLastScanSettings.singleScanFreqs.containsChannel(
4957e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                                    result.frequency)) {
4965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        singleScanResults.add(result);
4975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
49862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                    if (mLastScanSettings.hwPnoScanActive) {
49962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                        hwPnoScanResults.add(result);
500063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    }
5015fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
5029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    // was a cached result in wpa_supplicant
5039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
50541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
5065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings.backgroundScanActive) {
5075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanEventHandler != null) {
5085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((mLastScanSettings.reportEvents
5095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
5105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        for (ScanResult scanResult : backgroundScanResults) {
5115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            mBackgroundScanEventHandler.onFullScanResult(scanResult);
5125fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        }
51341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    }
51441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
51541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
5162771787818003e53e8175036a3d09688c783f350Mitchell Wills                Collections.sort(backgroundScanResults, SCAN_RESULT_SORT_COMPARATOR);
5175fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                ScanResult[] scanResultsArray = new ScanResult[Math.min(mLastScanSettings.maxAps,
5185fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            backgroundScanResults.size())];
5195fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                for (int i = 0; i < scanResultsArray.length; ++i) {
5205fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    scanResultsArray[i] = backgroundScanResults.get(i);
5215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
5229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if ((mLastScanSettings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
5245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanBuffer.add(new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
5255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    scanResultsArray));
5265fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
5279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanEventHandler != null) {
5295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((mLastScanSettings.reportEvents
5305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0
5315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            || (mLastScanSettings.reportEvents
5325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0
5335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            || (mLastScanSettings.reportEvents
5345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL
5355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    && (mBackgroundScanBuffer.size()
5365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            >= (mBackgroundScanBuffer.capacity()
5375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                    * mLastScanSettings.reportPercentThreshold
5385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                    / 100)
5395fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            || mBackgroundScanBuffer.size()
5405fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            >= mLastScanSettings.reportNumScansThreshold))) {
54163539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                        mBackgroundScanEventHandler
54263539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
5435fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
5449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5465fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mHotlistHandler != null) {
5475fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    int event = mHotlistChangeBuffer.processScan(backgroundScanResults);
5485fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((event & ChangeBuffer.EVENT_FOUND) != 0) {
5495fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mHotlistHandler.onHotlistApFound(
5505fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_FOUND));
5515fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
5525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((event & ChangeBuffer.EVENT_LOST) != 0) {
5535fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mHotlistHandler.onHotlistApLost(
5545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_LOST));
5555fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
5569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
55762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                // All background scan results when SW PNO scan is active will be reported to the
55862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                // PNO listener
55962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                if (mLastScanSettings.swPnoScanActive
56062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                        && mLastScanSettings.pnoScanEventHandler != null) {
56162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                   mLastScanSettings.pnoScanEventHandler.onPnoNetworkFound(scanResultsArray);
56262bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                }
5635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
5645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
5655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings.singleScanActive
5665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    && mLastScanSettings.singleScanEventHandler != null) {
5675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mLastScanSettings.reportSingleScanFullResults) {
5685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    for (ScanResult scanResult : singleScanResults) {
5695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult);
5705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
5719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5722771787818003e53e8175036a3d09688c783f350Mitchell Wills                Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
5735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mLatestSingleScanResult = new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
5745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
57563539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                mLastScanSettings.singleScanEventHandler
57663539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                        .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
5779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
57962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if (mLastScanSettings.hwPnoScanActive
580063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    && mLastScanSettings.pnoScanEventHandler != null) {
58162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                ScanResult[] pnoScanResultsArray = new ScanResult[hwPnoScanResults.size()];
582063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                for (int i = 0; i < pnoScanResultsArray.length; ++i) {
58362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                    pnoScanResultsArray[i] = hwPnoScanResults.get(i);
584063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                }
585063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                mLastScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray);
586063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius            }
587063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius
5885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mLastScanSettings = null;
5899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
5919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
5949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public WifiScanner.ScanData[] getLatestBatchedScanResults(boolean flush) {
5955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
5965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            WifiScanner.ScanData[] results = mBackgroundScanBuffer.get();
59741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            if (flush) {
5985fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mBackgroundScanBuffer.clear();
59941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
60041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            return results;
6019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
6039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6042332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    private boolean setNetworkPriorities(WifiNative.PnoNetwork[] networkList) {
6052332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        if (networkList != null) {
6062332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            if (DBG) Log.i(TAG, "Enable network and Set priorities for PNO.");
6072332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            for (WifiNative.PnoNetwork network : networkList) {
6082332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                if (!mWifiNative.setNetworkVariable(network.networkId,
6092332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                        WifiConfiguration.priorityVarName,
6102332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                        Integer.toString(network.priority))) {
6112332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    Log.e(TAG, "Set priority failed for: " + network.networkId);
6122332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    return false;
6132332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                }
61462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                if (!mWifiNative.enableNetworkWithoutConnect(network.networkId)) {
6152332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    Log.e(TAG, "Enable network failed for: " + network.networkId);
6162332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    return false;
6172332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                }
6182332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            }
6192332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
6202332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        return true;
6212332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6222332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
62362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private boolean startHwPnoScan() {
6242332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        if (!mWifiNative.enableBackgroundScan(true, null)) {
6252332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            return false;
6262332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
62762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        mHwPnoRunning = true;
6282332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        return true;
6292332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6302332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
63162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private boolean stopHwPnoScan() {
6322332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        if (!mWifiNative.enableBackgroundScan(false, null)) {
6332332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            return false;
6342332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
63562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        mHwPnoRunning = false;
6362332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        return true;
6372332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6382332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
63962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private boolean resumeHwPnoScan() {
64062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        if (!mHwPnoRunning) {
64162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            return startHwPnoScan();
6422332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
6432332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        return true;
6442332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6452332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
64662bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private boolean pauseHwPnoScan() {
64762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        if (mHwPnoRunning) {
64862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            return stopHwPnoScan();
6492332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
6502332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        return true;
6512332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6522332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
653dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    /**
654dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * Hw Pno Scan is required only for disconnected PNO when the device supports it.
655dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * @param isConnectedPno Whether this is connected PNO vs disconnected PNO.
656dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * @return true if HW PNO scan is required, false otherwise.
657dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     */
658dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    private boolean isHwPnoScanRequired(boolean isConnectedPno) {
659dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        return (!isConnectedPno & mHwPnoScanSupported);
660dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    }
661dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius
662dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    private boolean isHwPnoScanRequired() {
663dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        if (mPnoSettings == null) return false;
664dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        return isHwPnoScanRequired(mPnoSettings.isConnected);
665dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    }
666dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius
667dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    /**
668dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * Sw Pno Scan is required for all connected PNO and for devices those don't support
669dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * HW disconnected PNOscans.
670dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * @param isConnectedPno Whether this is connected PNO vs disconnected PNO.
671dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * @return true if SW PNO scan is required, false otherwise.
672dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     */
673dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    private boolean isSwPnoScanRequired(boolean isConnectedPno) {
674dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        return (isConnectedPno || !mHwPnoScanSupported);
675dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    }
676dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius
677dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    private boolean isSwPnoScanRequired() {
678dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        if (mPnoSettings == null) return false;
679dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        return isSwPnoScanRequired(mPnoSettings.isConnected);
680dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    }
681dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius
6822332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    @Override
6832332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    public boolean setPnoList(WifiNative.PnoSettings settings,
6842332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            WifiNative.PnoEventHandler eventHandler) {
6852332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        synchronized (mSettingsLock) {
6862332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            if (mPnoSettings != null) {
6872332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                Log.w(TAG, "Already running a PNO scan");
6882332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                return false;
6892332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            }
6902332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoEventHandler = eventHandler;
6912332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoSettings = settings;
69262bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if (mHwPnoScanSupported) {
69362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                if (!setNetworkPriorities(settings.networkList)) return false;
69462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                // For supplicant based PNO, we start the scan immediately when we set pno list.
69562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                processPendingScans();
69662bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            }
6972332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            return true;
6982332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
6992332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
7002332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
7012332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    @Override
7022332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    public boolean resetPnoList(WifiNative.PnoSettings settings) {
7032332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        synchronized (mSettingsLock) {
7042332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            if (mPnoSettings == null) {
7052332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                Log.w(TAG, "No PNO scan running");
7062332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                return false;
7072332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            }
7082332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoEventHandler = null;
7092332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoSettings = null;
71062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if (mHwPnoScanSupported) {
71162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                // For supplicant based PNO, we stop the scan immediately when we reset pno list.
71262bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                return stopHwPnoScan();
71362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            } else {
71462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                return true;
71562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            }
7162332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
7172332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
7182332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
7192332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    @Override
720dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    public boolean shouldScheduleBackgroundScanForPno(boolean isConnectedPno) {
721dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        // If PNO scan is not supported by the HW or if this is a connected PNO request, revert to
722dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        // using a normal periodic background scan.
723dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        return !isHwPnoScanRequired(isConnectedPno);
7242332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
7252332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
7269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
7279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean setHotlist(WifiScanner.HotlistSettings settings,
7289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.HotlistEventHandler eventHandler) {
7299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings == null || eventHandler == null) {
7309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
7319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
7339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = eventHandler;
7349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.setSettings(settings.bssidInfos, settings.apLostThreshold, 1);
7359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
7369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
7389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
7399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
7409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void resetHotlist() {
7415fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
7429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.clearSettings();
7439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = null;
7449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
7469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
74794bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    /*
74894bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills     * Significant Wifi Change API is not implemented
74994bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills     */
75094bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    @Override
75194bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    public boolean trackSignificantWifiChange(WifiScanner.WifiChangeSettings settings,
75294bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills            WifiNative.SignificantWifiChangeEventHandler handler) {
75394bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills        return false;
75494bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    }
75594bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    @Override
75694bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    public void untrackSignificantWifiChange() {}
75794bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills
75894bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills
7599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class LastScanSettings {
7605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public long startTime;
7615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
7625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public LastScanSettings(long startTime) {
7635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.startTime = startTime;
7645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
7655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
7665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        // Background settings
7675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean backgroundScanActive = false;
7685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int scanId;
7695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int maxAps;
7705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportEvents;
7715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportNumScansThreshold;
7725fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportPercentThreshold;
7735fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
7745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public void setBackgroundScan(int scanId, int maxAps, int reportEvents,
7759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int reportNumScansThreshold, int reportPercentThreshold) {
7765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.backgroundScanActive = true;
7779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.scanId = scanId;
7789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.maxAps = maxAps;
7799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportEvents = reportEvents;
7809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportNumScansThreshold = reportNumScansThreshold;
7819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportPercentThreshold = reportPercentThreshold;
7829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
7845fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        // Single scan settings
7855fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean singleScanActive = false;
7865fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean reportSingleScanFullResults;
7877e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills        public ChannelCollection singleScanFreqs;
7885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public WifiNative.ScanEventHandler singleScanEventHandler;
7895fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
7905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public void setSingleScan(boolean reportSingleScanFullResults,
7917e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                ChannelCollection singleScanFreqs,
7927e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                WifiNative.ScanEventHandler singleScanEventHandler) {
7935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            singleScanActive = true;
7945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.reportSingleScanFullResults = reportSingleScanFullResults;
7955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.singleScanFreqs = singleScanFreqs;
7965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.singleScanEventHandler = singleScanEventHandler;
7975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
798063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius
79962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        public boolean hwPnoScanActive = false;
80062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        public boolean swPnoScanActive = false;
801063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius        public WifiNative.PnoEventHandler pnoScanEventHandler;
802063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius
80362bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius
80462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        public void setHwPnoScan(WifiNative.PnoEventHandler pnoScanEventHandler) {
80562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            hwPnoScanActive = true;
80662bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            this.pnoScanEventHandler = pnoScanEventHandler;
80762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        }
80862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius
80962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        public void setSwPnoScan(WifiNative.PnoEventHandler pnoScanEventHandler) {
81062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            swPnoScanActive = true;
811063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius            this.pnoScanEventHandler = pnoScanEventHandler;
812063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius        }
8139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
8149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ScanBuffer {
8179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private final ArrayDeque<WifiScanner.ScanData> mBuffer;
8185fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        private int mCapacity;
8199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanBuffer(int capacity) {
8215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mCapacity = capacity;
8225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBuffer = new ArrayDeque<>(mCapacity);
8239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int size() {
8269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.size();
8279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int capacity() {
8305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return mCapacity;
8319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public boolean isFull() {
8345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return size() == mCapacity;
8359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void add(WifiScanner.ScanData scanData) {
8389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (isFull()) {
8399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mBuffer.pollFirst();
8409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
8419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.offerLast(scanData);
8429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clear() {
8459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.clear();
8469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public WifiScanner.ScanData[] get() {
8499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.toArray(new WifiScanner.ScanData[mBuffer.size()]);
8509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
8529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ChangeBuffer {
8549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_NONE = 0;
8559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_LOST = 1;
8569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_FOUND = 2;
8579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public static int STATE_FOUND = 0;
8599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private WifiScanner.BssidInfo[] mBssidInfos = null;
8619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mApLostThreshold;
8629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mMinEvents;
8639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mLostCount = null;
8649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private ScanResult[] mMostRecentResult = null;
8659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mPendingEvent = null;
8669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private boolean mFiredEvents = false;
8679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        private static ScanResult findResult(List<ScanResult> results, String bssid) {
8695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            for (int i = 0; i < results.size(); ++i) {
8705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (bssid.equalsIgnoreCase(results.get(i).BSSID)) {
8715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    return results.get(i);
8729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
8739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
8749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return null;
8759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void setSettings(WifiScanner.BssidInfo[] bssidInfos, int apLostThreshold,
8789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                int minEvents) {
8799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBssidInfos = bssidInfos;
8809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (apLostThreshold <= 0) {
8819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = 1;
8825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            } else {
8839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = apLostThreshold;
8849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
8859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mMinEvents = minEvents;
8869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (bssidInfos != null) {
8879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = new int[bssidInfos.length];
8889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Arrays.fill(mLostCount, mApLostThreshold); // default to lost
8899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = new ScanResult[bssidInfos.length];
8909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = new int[bssidInfos.length];
8919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
8925fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            } else {
8939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = null;
8949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = null;
8959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = null;
8969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
8979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clearSettings() {
9009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            setSettings(null, 0, 0);
9019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
9029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
9049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Get the most recent scan results for APs that triggered the given event on the last call
9059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * to {@link #processScan}.
9069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
9079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanResult[] getLastResults(int event) {
9089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanResult> results = new ArrayList<>();
9099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
9109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] == event) {
9119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    results.add(mMostRecentResult[i]);
9129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return results.toArray(new ScanResult[results.size()]);
9159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
9169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
9189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Process the supplied scan results and determine if any events should be generated based
9199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * on the configured settings
9209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * @return The events that occurred
9219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
9225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int processScan(List<ScanResult> scanResults) {
9239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mBssidInfos == null) {
9249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return EVENT_NONE;
9259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // clear events from last time
9289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mFiredEvents) {
9299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
9309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                for (int i = 0; i < mLostCount.length; ++i) {
9319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mPendingEvent[i] = EVENT_NONE;
9329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventCount = 0;
9369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventType = EVENT_NONE;
9379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
9389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = findResult(scanResults, mBssidInfos[i].bssid);
9399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int rssi = Integer.MIN_VALUE;
9409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (result != null) {
9419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mMostRecentResult[i] = result;
9429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    rssi = result.level;
9439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (rssi < mBssidInfos[i].low) {
9469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] < mApLostThreshold) {
9479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        mLostCount[i]++;
9489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mLostCount[i] >= mApLostThreshold) {
9509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            if (mPendingEvent[i] == EVENT_FOUND) {
9519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_NONE;
9525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            } else {
9539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_LOST;
9549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
9559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
9569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
9575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
9589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] >= mApLostThreshold) {
9599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mPendingEvent[i] == EVENT_LOST) {
9609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_NONE;
9615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        } else {
9629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_FOUND;
9639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
9649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
9659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mLostCount[i] = STATE_FOUND;
9669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (DBG) {
9685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    Log.d(TAG, "ChangeBuffer BSSID: " + mBssidInfos[i].bssid + "=" + mLostCount[i]
9695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            + ", " + mPendingEvent[i] + ", rssi=" + rssi);
9709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] != EVENT_NONE) {
9729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    ++eventCount;
9739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    eventType |= mPendingEvent[i];
9749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "ChangeBuffer events count=" + eventCount + ": " + eventType);
9779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (eventCount >= mMinEvents) {
9789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = true;
9799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return eventType;
9809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return EVENT_NONE;
9829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
9839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
9849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills}
985