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
17a8367288377cbaed6371256ca837b7aa22280706Mitchell Willspackage com.android.server.wifi.scanner;
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.util.Log;
289ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Piusimport com.android.internal.R;
30ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Piusimport com.android.server.wifi.Clock;
31a8367288377cbaed6371256ca837b7aa22280706Mitchell Willsimport com.android.server.wifi.ScanDetail;
32a8367288377cbaed6371256ca837b7aa22280706Mitchell Willsimport com.android.server.wifi.WifiMonitor;
33a8367288377cbaed6371256ca837b7aa22280706Mitchell Willsimport com.android.server.wifi.WifiNative;
347e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Willsimport com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
357e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills
369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.ArrayDeque;
379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.ArrayList;
389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Arrays;
399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Collections;
40d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Piusimport java.util.HashSet;
419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.List;
429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willsimport java.util.Set;
439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
44f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills/**
455fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills * Implementation of the WifiScanner HAL API that uses wpa_supplicant to perform all scans
46a8367288377cbaed6371256ca837b7aa22280706Mitchell Wills * @see com.android.server.wifi.scanner.WifiScannerImpl for more details on each method.
47f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills */
489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Willspublic class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handler.Callback {
499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final String TAG = "SupplicantWifiScannerImpl";
509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final boolean DBG = false;
519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
529d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    public static final String BACKGROUND_PERIOD_ALARM_TAG = TAG + " Background Scan Period";
539d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    public static final String TIMEOUT_ALARM_TAG = TAG + " Scan Timeout";
54362fad8eddd674d7cf19ffcc1fec38d2d2ee2f53Roshan Pius    // Max number of networks that can be specified to wpa_supplicant per scan request
55362fad8eddd674d7cf19ffcc1fec38d2d2ee2f53Roshan Pius    public static final int MAX_HIDDEN_NETWORK_IDS_PER_SCAN = 16;
569d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills
579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int SCAN_BUFFER_CAPACITY = 10;
589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int MAX_APS_PER_SCAN = 32;
599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final int MAX_SCAN_BUCKETS = 16;
609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static final String ACTION_SCAN_PERIOD =
629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            "com.android.server.util.SupplicantWifiScannerImpl.action.SCAN_PERIOD";
639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final Context mContext;
659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final WifiNative mWifiNative;
669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final AlarmManager mAlarmManager;
679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private final Handler mEventHandler;
687e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    private final ChannelHelper mChannelHelper;
69ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius    private final Clock mClock;
709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private Object mSettingsLock = new Object();
729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Next scan settings to apply when the previous scan completes
745fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mPendingBackgroundScanSettings = null;
755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mPendingBackgroundScanEventHandler = null;
765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mPendingSingleScanSettings = null;
775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mPendingSingleScanEventHandler = null;
785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    // Active background scan settings/state
805fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanSettings mBackgroundScanSettings = null;
815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiNative.ScanEventHandler mBackgroundScanEventHandler = null;
825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private int mNextBackgroundScanPeriod = 0;
835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private int mNextBackgroundScanId = 0;
845fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private boolean mBackgroundScanPeriodPending = false;
855fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private boolean mBackgroundScanPaused = false;
865fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private ScanBuffer mBackgroundScanBuffer = new ScanBuffer(SCAN_BUFFER_CAPACITY);
875fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private WifiScanner.ScanData mLatestSingleScanResult =
895fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            new WifiScanner.ScanData(0, 0, new ScanResult[0]);
905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
915fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    // Settings for the currently running scan, null if no scan active
929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private LastScanSettings mLastScanSettings = null;
939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    // Active hotlist settings
959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private WifiNative.HotlistEventHandler mHotlistHandler = null;
969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private ChangeBuffer mHotlistChangeBuffer = new ChangeBuffer();
979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
989153bd67d51b305ffdd61355e0748e3c332c2cafRoshan Pius    // Pno related info.
99063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius    private WifiNative.PnoSettings mPnoSettings = null;
1009153bd67d51b305ffdd61355e0748e3c332c2cafRoshan Pius    private WifiNative.PnoEventHandler mPnoEventHandler;
10162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private final boolean mHwPnoScanSupported;
102e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    private final HwPnoDebouncer mHwPnoDebouncer;
103e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    private final HwPnoDebouncer.Listener mHwPnoDebouncerListener = new HwPnoDebouncer.Listener() {
104e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        public void onPnoScanFailed() {
105e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            Log.e(TAG, "Pno scan failure received");
106e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            reportPnoScanFailure();
107e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
108e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    };
1099153bd67d51b305ffdd61355e0748e3c332c2cafRoshan Pius
1109d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    /**
1119d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills     * Duration to wait before timing out a scan.
1129d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills     *
1139d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills     * The expected behavior is that the hardware will return a failed scan if it does not
1149d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills     * complete, but timeout just in case it does not.
1159d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills     */
116a85fc1b07490d3ff194a98fe7389f6697ace5801Roshan Pius    private static final long SCAN_TIMEOUT_MS = 15000;
1179d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills
11841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills    AlarmManager.OnAlarmListener mScanPeriodListener = new AlarmManager.OnAlarmListener() {
11941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            public void onAlarm() {
12041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                synchronized (mSettingsLock) {
12141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    handleScanPeriod();
12241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
12341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
12441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        };
12541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
1269d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    AlarmManager.OnAlarmListener mScanTimeoutListener = new AlarmManager.OnAlarmListener() {
1279d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills            public void onAlarm() {
1289d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                synchronized (mSettingsLock) {
1299d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                    handleScanTimeout();
1309d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                }
1319d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills            }
1329d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills        };
1339d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills
1342332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    public SupplicantWifiScannerImpl(Context context, WifiNative wifiNative,
135ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            ChannelHelper channelHelper, Looper looper, Clock clock) {
1369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mContext = context;
1379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mWifiNative = wifiNative;
1382332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        mChannelHelper = channelHelper;
1399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
1409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        mEventHandler = new Handler(looper, this);
141ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        mClock = clock;
142ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        mHwPnoDebouncer = new HwPnoDebouncer(mWifiNative, mAlarmManager, mEventHandler, mClock);
1437d2d8c27647676c51208e417afbb8dd6c6784b7cMitchell Wills
14462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        // Check if the device supports HW PNO scans.
14562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        mHwPnoScanSupported = mContext.getResources().getBoolean(
14662bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                R.bool.config_wifi_background_scan_support);
14762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius
1488adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills        WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
1498adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills                WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
1508adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills        WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
1518adb4e72f58e3e25918f33e0b2687e6acc14c47dMitchell Wills                WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
1529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
154ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius    public SupplicantWifiScannerImpl(Context context, WifiNative wifiNative, Looper looper,
155ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            Clock clock) {
1562332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        // TODO figure out how to get channel information from supplicant
157ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        this(context, wifiNative, new NoBandChannelHelper(), looper, clock);
1582332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
1592332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
1609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1611e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills    public void cleanup() {
1621e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        synchronized (mSettingsLock) {
1631e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mPendingSingleScanSettings = null;
1641e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mPendingSingleScanEventHandler = null;
16562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            stopHwPnoScan();
1661e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            stopBatchedScan();
1671e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            resetHotlist();
1681e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            untrackSignificantWifiChange();
1691e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mLastScanSettings = null; // finally clear any active scan
1701e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        }
1711e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills    }
1721e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills
1731e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills    @Override
1749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
1759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_cache_size = Integer.MAX_VALUE;
1769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_buckets = MAX_SCAN_BUCKETS;
1779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_ap_cache_per_scan = MAX_APS_PER_SCAN;
1789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_rssi_sample_size = 8;
1799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_scan_reporting_threshold = SCAN_BUFFER_CAPACITY;
1809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_hotlist_bssids = 0;
1819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        capabilities.max_significant_wifi_change_aps = 0;
1825ed43368643dab64c83bfb15e14ab59d63645c6fMitchell Wills        return true;
1839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
1859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
1867e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    public ChannelHelper getChannelHelper() {
1877e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills        return mChannelHelper;
1887e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    }
1897e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills
1907e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills    @Override
191f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    public boolean startSingleScan(WifiNative.ScanSettings settings,
192f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills            WifiNative.ScanEventHandler eventHandler) {
1935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (eventHandler == null || settings == null) {
1945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings
1955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + ",eventHandler=" + eventHandler);
1965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return false;
1975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
1985fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (mPendingSingleScanSettings != null
1995fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
2005fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "A single scan is already running");
2015fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return false;
2025fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2045fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingSingleScanSettings = settings;
2055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingSingleScanEventHandler = eventHandler;
2065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            processPendingScans();
2075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return true;
2085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
209f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    }
210f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills
211f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    @Override
212f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    public WifiScanner.ScanData getLatestSingleScanResults() {
2135fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        return mLatestSingleScanResult;
214f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    }
215f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills
216f2f6f79242454ff9161f5af772292fa0180436f8Mitchell Wills    @Override
2179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean startBatchedScan(WifiNative.ScanSettings settings,
2189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.ScanEventHandler eventHandler) {
2195fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings == null || eventHandler == null) {
2205fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            Log.w(TAG, "Invalid arguments for startBatched: settings=" + settings
2215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + ",eventHandler=" + eventHandler);
2229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.max_ap_per_scan < 0 || settings.max_ap_per_scan > MAX_APS_PER_SCAN) {
2269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2275fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.num_buckets < 0 || settings.num_buckets > MAX_SCAN_BUCKETS) {
2299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.report_threshold_num_scans < 0
2325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                || settings.report_threshold_num_scans > SCAN_BUFFER_CAPACITY) {
2339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.report_threshold_percent < 0 || settings.report_threshold_percent > 100) {
2369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        if (settings.base_period_ms <= 0) {
2399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
2405fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
2419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        for (int i = 0; i < settings.num_buckets; ++i) {
2429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.BucketSettings bucket = settings.buckets[i];
2435fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (bucket.period_ms % settings.base_period_ms != 0) {
2449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return false;
2455fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
2469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2485fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            stopBatchedScan();
2505cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills            if (DBG) {
2515cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills                Log.d(TAG, "Starting scan num_buckets=" + settings.num_buckets + ", base_period="
2525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    + settings.base_period_ms + " ms");
2535cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills            }
2545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanSettings = settings;
2555fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanEventHandler = eventHandler;
2569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod(); // Try to start scan immediately
2579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
2589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void stopBatchedScan() {
2635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Stopping scan");
2655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanSettings = null;
2665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanEventHandler = null;
2675fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanSettings = null;
2685fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mPendingBackgroundScanEventHandler = null;
2695fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = false;
2705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = false;
2719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
2729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2731e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        processPendingScans();
2749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
2779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void pauseBatchedScan() {
2785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
2795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Pausing scan");
2809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // if there isn't a pending scan then make the current scan pending
2815fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanSettings == null) {
2825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanSettings = mBackgroundScanSettings;
2835fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler = mBackgroundScanEventHandler;
2849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
2855fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanSettings = null;
2865fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanEventHandler = null;
2875fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = false;
2885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = true;
2899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            unscheduleScansLocked();
2919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
2929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiScanner.ScanData[] results = getLatestBatchedScanResults(/* flush = */ true);
2935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanEventHandler != null) {
2945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler.onScanPaused(results);
2955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
2969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
2971e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        processPendingScans();
2989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
2999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
3019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void restartBatchedScan() {
3025fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
3035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Restarting scan");
3045fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingBackgroundScanEventHandler != null) {
3055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingBackgroundScanEventHandler.onScanRestarted();
3065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
3075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPaused = false;
3089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            handleScanPeriod();
3099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
3109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void unscheduleScansLocked() {
31341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills        mAlarmManager.cancel(mScanPeriodListener);
3141e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        if (mLastScanSettings != null) {
3151e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills            mLastScanSettings.backgroundScanActive = false;
3161e806a7aac77f6f65ba299329e1fc452e0148b8dMitchell Wills        }
3179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
3189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void handleScanPeriod() {
3205fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
3215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBackgroundScanPeriodPending = true;
3225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            processPendingScans();
3235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
3245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    }
3255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
3269d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    private void handleScanTimeout() {
3279d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills        Log.e(TAG, "Timed out waiting for scan result from supplicant");
3289d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills        reportScanFailure();
3299d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills        processPendingScans();
3309d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    }
3319d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills
3321bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius    private boolean isDifferentPnoScanSettings(LastScanSettings newScanSettings) {
3331bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius        return (mLastScanSettings == null || !Arrays.equals(
3341bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                newScanSettings.pnoNetworkList, mLastScanSettings.pnoNetworkList));
3351bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius    }
3361bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius
3375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills    private void processPendingScans() {
3385fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
33962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            // Wait for the active scan result to come back to reschedule other scans,
34062bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            // unless if HW pno scan is running. Hw PNO scans are paused it if there
34162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            // are other pending scans,
34262bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if (mLastScanSettings != null && !mLastScanSettings.hwPnoScanActive) {
3439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
3449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
3459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3467e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills            ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
347d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius            Set<Integer> hiddenNetworkIdSet = new HashSet<Integer>();
34863539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills            final LastScanSettings newScanSettings =
349ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                    new LastScanSettings(mClock.elapsedRealtime());
3509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
3515fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            // Update scan settings if there is a pending scan
3525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (!mBackgroundScanPaused) {
3535fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mPendingBackgroundScanSettings != null) {
3545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanSettings = mPendingBackgroundScanSettings;
3555fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanEventHandler = mPendingBackgroundScanEventHandler;
3565fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mNextBackgroundScanPeriod = 0;
3575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mPendingBackgroundScanSettings = null;
3585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mPendingBackgroundScanEventHandler = null;
3595fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanPeriodPending = true;
3605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
3610d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                if (mBackgroundScanPeriodPending && mBackgroundScanSettings != null) {
3620d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                    int reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; // default to no batch
3630d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                    for (int bucket_id = 0; bucket_id < mBackgroundScanSettings.num_buckets;
3640d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            ++bucket_id) {
3650d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                        WifiNative.BucketSettings bucket =
3660d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                mBackgroundScanSettings.buckets[bucket_id];
3670d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                        if (mNextBackgroundScanPeriod % (bucket.period_ms
3680d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                        / mBackgroundScanSettings.base_period_ms) == 0) {
3690d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            if ((bucket.report_events
3700d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                            & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) {
3710d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                reportEvents |= WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
3729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
3730d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            if ((bucket.report_events
3740d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                            & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
3750d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
3760d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            }
3770d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            // only no batch if all buckets specify it
3780d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            if ((bucket.report_events
3790d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                            & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
3800d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                reportEvents &= ~WifiScanner.REPORT_EVENT_NO_BATCH;
3810d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            }
3820d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal
3830d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            allFreqs.addChannels(bucket);
3849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
3850d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                    }
3860d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                    if (!allFreqs.isEmpty()) {
3870d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                        newScanSettings.setBackgroundScan(mNextBackgroundScanId++,
3880d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                mBackgroundScanSettings.max_ap_per_scan, reportEvents,
3890d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                mBackgroundScanSettings.report_threshold_num_scans,
3900d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                mBackgroundScanSettings.report_threshold_percent);
3910d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                    }
39262bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius
3930d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                    int[] hiddenNetworkIds = mBackgroundScanSettings.hiddenNetworkIds;
3940d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                    if (hiddenNetworkIds != null) {
3950d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                        int numHiddenNetworkIds = Math.min(hiddenNetworkIds.length,
3960d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                                MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
3970d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                        for (int i = 0; i < numHiddenNetworkIds; i++) {
3980d0a4c339b3950ad6d882e89223dc21a89ef3953John Eckerdal                            hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
399d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                        }
4009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
4015fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
4025fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mNextBackgroundScanPeriod++;
4035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanPeriodPending = false;
404ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
405ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                            mClock.elapsedRealtime() + mBackgroundScanSettings.base_period_ms,
4069d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                            BACKGROUND_PERIOD_ALARM_TAG, mScanPeriodListener, mEventHandler);
4079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
4095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
4105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mPendingSingleScanSettings != null) {
4115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                boolean reportFullResults = false;
4127e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                ChannelCollection singleScanFreqs = mChannelHelper.createChannelCollection();
4135fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                for (int i = 0; i < mPendingSingleScanSettings.num_buckets; ++i) {
4145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    WifiNative.BucketSettings bucketSettings =
4155fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            mPendingSingleScanSettings.buckets[i];
4165fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((bucketSettings.report_events
4175fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
4185fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        reportFullResults = true;
4199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
4207e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                    singleScanFreqs.addChannels(bucketSettings);
4217e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                    allFreqs.addChannels(bucketSettings);
4229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
4235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                newScanSettings.setSingleScan(reportFullResults, singleScanFreqs,
4245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mPendingSingleScanEventHandler);
425d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                int[] hiddenNetworkIds = mPendingSingleScanSettings.hiddenNetworkIds;
426d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                if (hiddenNetworkIds != null) {
427362fad8eddd674d7cf19ffcc1fec38d2d2ee2f53Roshan Pius                    int numHiddenNetworkIds = Math.min(hiddenNetworkIds.length,
428362fad8eddd674d7cf19ffcc1fec38d2d2ee2f53Roshan Pius                            MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
429362fad8eddd674d7cf19ffcc1fec38d2d2ee2f53Roshan Pius                    for (int i = 0; i < numHiddenNetworkIds; i++) {
430d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                        hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
431d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                    }
432d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                }
4335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingSingleScanSettings = null;
4345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mPendingSingleScanEventHandler = null;
4355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
4365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
43762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if ((newScanSettings.backgroundScanActive || newScanSettings.singleScanActive)
43862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                    && !allFreqs.isEmpty()) {
43962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                pauseHwPnoScan();
4407e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                Set<Integer> freqs = allFreqs.getSupplicantScanFreqs();
441d74ff28cdb01d3f711e0b0f0e99e51fdb221eaf2Roshan Pius                boolean success = mWifiNative.scan(freqs, hiddenNetworkIdSet);
4425fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (success) {
4435fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    // TODO handle scan timeout
4445cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills                    if (DBG) {
4455cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills                        Log.d(TAG, "Starting wifi scan for freqs=" + freqs
4465cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills                                + ", background=" + newScanSettings.backgroundScanActive
4475cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills                                + ", single=" + newScanSettings.singleScanActive);
4485cdc80d103ebd2935693a8d855162d55bed2821cMitchell Wills                    }
4495fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mLastScanSettings = newScanSettings;
450ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
451ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                            mClock.elapsedRealtime() + SCAN_TIMEOUT_MS,
4529d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                            TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
4535fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
45463539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    Log.e(TAG, "Failed to start scan, freqs=" + freqs);
45563539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    // indicate scan failure async
45663539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                    mEventHandler.post(new Runnable() {
45763539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                            public void run() {
45863539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                if (newScanSettings.singleScanEventHandler != null) {
45963539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                    newScanSettings.singleScanEventHandler
46063539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                            .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
46163539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                }
46263539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                            }
46363539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                        });
4649d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                    // TODO(b/27769665) background scans should be failed too if scans fail enough
4655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
466dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius            } else if (isHwPnoScanRequired()) {
4671bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                newScanSettings.setHwPnoScan(mPnoSettings.networkList, mPnoEventHandler);
4681bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                boolean status;
4691bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                // If the PNO network list has changed from the previous request, ensure that
4701bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                // we bypass the debounce logic and restart PNO scan.
4711bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                if (isDifferentPnoScanSettings(newScanSettings)) {
4721bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                    status = restartHwPnoScan();
4731bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                } else {
4741bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                    status = startHwPnoScan();
4751bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                }
4761bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                if (status) {
477063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    mLastScanSettings = newScanSettings;
478063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                } else {
479063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    Log.e(TAG, "Failed to start PNO scan");
480063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    // indicate scan failure async
481063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    mEventHandler.post(new Runnable() {
482063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                        public void run() {
483063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            if (mPnoEventHandler != null) {
484063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                                mPnoEventHandler.onPnoScanFailed();
485063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            }
486063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            // Clean up PNO state, we don't want to continue PNO scanning.
487063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            mPnoSettings = null;
488063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                            mPnoEventHandler = null;
489063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                        }
490063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    });
491063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                }
4929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
4939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
4949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
4959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
4969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
4979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean handleMessage(Message msg) {
4989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        switch(msg.what) {
4999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_FAILED_EVENT:
5009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Log.w(TAG, "Scan failed");
5019d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                mAlarmManager.cancel(mScanTimeoutListener);
5029d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                reportScanFailure();
5035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                processPendingScans();
5049ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
5059ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            case WifiMonitor.SCAN_RESULTS_EVENT:
5069d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                mAlarmManager.cancel(mScanTimeoutListener);
5079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                pollLatestScanData();
5085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                processPendingScans();
5099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                break;
5109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            default:
5119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                // ignore unknown event
5129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
5139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        return true;
5149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
5159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5169d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    private void reportScanFailure() {
5179d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills        synchronized (mSettingsLock) {
5189d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills            if (mLastScanSettings != null) {
5199d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                if (mLastScanSettings.singleScanEventHandler != null) {
5209d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                    mLastScanSettings.singleScanEventHandler
5219d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                            .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
5229d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                }
5239d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                // TODO(b/27769665) background scans should be failed too if scans fail enough
5249d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills                mLastScanSettings = null;
5259d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills            }
5269d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills        }
5279d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills    }
5289d0c558cab7c80a572a32ae70d501df15367fd5fMitchell Wills
529e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    private void reportPnoScanFailure() {
530e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        synchronized (mSettingsLock) {
531e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            if (mLastScanSettings != null && mLastScanSettings.hwPnoScanActive) {
532e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                if (mLastScanSettings.pnoScanEventHandler != null) {
533e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                    mLastScanSettings.pnoScanEventHandler.onPnoScanFailed();
534e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                }
535e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                // Clean up PNO state, we don't want to continue PNO scanning.
536e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                mPnoSettings = null;
537e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                mPnoEventHandler = null;
538e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                mLastScanSettings = null;
539e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            }
540e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
541e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    }
542e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
5439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private void pollLatestScanData() {
5445fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
5455fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings == null) {
5469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                 // got a scan before we started scanning or after scan was canceled
5479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return;
5489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
5499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5505fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId);
5519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanDetail> nativeResults = mWifiNative.getScanResults();
5525fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            List<ScanResult> singleScanResults = new ArrayList<>();
5535fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            List<ScanResult> backgroundScanResults = new ArrayList<>();
55462bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            List<ScanResult> hwPnoScanResults = new ArrayList<>();
5559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < nativeResults.size(); ++i) {
5569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = nativeResults.get(i).getScanResult();
5579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                long timestamp_ms = result.timestamp / 1000; // convert us -> ms
5589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (timestamp_ms > mLastScanSettings.startTime) {
5595fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mLastScanSettings.backgroundScanActive) {
5605fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        backgroundScanResults.add(result);
5615fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
5625fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if (mLastScanSettings.singleScanActive
5637e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                            && mLastScanSettings.singleScanFreqs.containsChannel(
5647e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                                    result.frequency)) {
5655fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        singleScanResults.add(result);
5665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
56762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                    if (mLastScanSettings.hwPnoScanActive) {
56862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                        hwPnoScanResults.add(result);
569063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    }
5705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
5719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    // was a cached result in wpa_supplicant
5729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
5739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
57441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
5755fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings.backgroundScanActive) {
5765fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanEventHandler != null) {
5775fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((mLastScanSettings.reportEvents
5785fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
5795fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        for (ScanResult scanResult : backgroundScanResults) {
580c9e6069eb941d282af213dc20b171877db6b567bMitchell Wills                            // TODO(b/27506257): Fill in correct bucketsScanned value
581c9e6069eb941d282af213dc20b171877db6b567bMitchell Wills                            mBackgroundScanEventHandler.onFullScanResult(scanResult, 0);
5825fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        }
58341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                    }
58441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills                }
58541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills
5862771787818003e53e8175036a3d09688c783f350Mitchell Wills                Collections.sort(backgroundScanResults, SCAN_RESULT_SORT_COMPARATOR);
5875fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                ScanResult[] scanResultsArray = new ScanResult[Math.min(mLastScanSettings.maxAps,
5885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            backgroundScanResults.size())];
5895fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                for (int i = 0; i < scanResultsArray.length; ++i) {
5905fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    scanResultsArray[i] = backgroundScanResults.get(i);
5915fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
5929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if ((mLastScanSettings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
594c9e6069eb941d282af213dc20b171877db6b567bMitchell Wills                    // TODO(b/27506257): Fill in correct bucketsScanned value
5955fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    mBackgroundScanBuffer.add(new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
5965fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    scanResultsArray));
5975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                }
5989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
5995fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mBackgroundScanEventHandler != null) {
6005fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((mLastScanSettings.reportEvents
6015fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0
6025fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            || (mLastScanSettings.reportEvents
6035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0
6045fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            || (mLastScanSettings.reportEvents
6055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL
6065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                    && (mBackgroundScanBuffer.size()
6075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            >= (mBackgroundScanBuffer.capacity()
6085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                    * mLastScanSettings.reportPercentThreshold
6095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                                    / 100)
6105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            || mBackgroundScanBuffer.size()
6115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                            >= mLastScanSettings.reportNumScansThreshold))) {
61263539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                        mBackgroundScanEventHandler
61363539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                                .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
6145fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
6159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
6169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6175fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mHotlistHandler != null) {
6185fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    int event = mHotlistChangeBuffer.processScan(backgroundScanResults);
6195fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((event & ChangeBuffer.EVENT_FOUND) != 0) {
6205fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mHotlistHandler.onHotlistApFound(
6215fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_FOUND));
6225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
6235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    if ((event & ChangeBuffer.EVENT_LOST) != 0) {
6245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        mHotlistHandler.onHotlistApLost(
6255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                                mHotlistChangeBuffer.getLastResults(ChangeBuffer.EVENT_LOST));
6265fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
6279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
6285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            }
6295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
6305fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (mLastScanSettings.singleScanActive
6315fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    && mLastScanSettings.singleScanEventHandler != null) {
6325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (mLastScanSettings.reportSingleScanFullResults) {
6335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    for (ScanResult scanResult : singleScanResults) {
634c9e6069eb941d282af213dc20b171877db6b567bMitchell Wills                        // ignore buckets scanned since there is only one bucket for a single scan
635c9e6069eb941d282af213dc20b171877db6b567bMitchell Wills                        mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult,
636c9e6069eb941d282af213dc20b171877db6b567bMitchell Wills                                /* bucketsScanned */ 0);
6375fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    }
6389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
6392771787818003e53e8175036a3d09688c783f350Mitchell Wills                Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
6404e1f32efceee1db37bfb1e2624b434dbfb055686Mitchell Wills                mLatestSingleScanResult = new WifiScanner.ScanData(mLastScanSettings.scanId, 0, 0,
6414e1f32efceee1db37bfb1e2624b434dbfb055686Mitchell Wills                        mLastScanSettings.singleScanFreqs.isAllChannels(),
6425fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
64363539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                mLastScanSettings.singleScanEventHandler
64463539f1283899fbbf83ab90757961b4be51d5034Mitchell Wills                        .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
6459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
6465fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
64762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            if (mLastScanSettings.hwPnoScanActive
648063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                    && mLastScanSettings.pnoScanEventHandler != null) {
64962bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                ScanResult[] pnoScanResultsArray = new ScanResult[hwPnoScanResults.size()];
650063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                for (int i = 0; i < pnoScanResultsArray.length; ++i) {
65162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                    pnoScanResultsArray[i] = hwPnoScanResults.get(i);
652063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                }
653063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius                mLastScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray);
654063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius            }
655063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius
6565fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mLastScanSettings = null;
6579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6589ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
6599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
6629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public WifiScanner.ScanData[] getLatestBatchedScanResults(boolean flush) {
6635fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
6645fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            WifiScanner.ScanData[] results = mBackgroundScanBuffer.get();
66541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            if (flush) {
6665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                mBackgroundScanBuffer.clear();
66741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            }
66841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills            return results;
6699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
6709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
6719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
6722332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    private boolean setNetworkPriorities(WifiNative.PnoNetwork[] networkList) {
6732332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        if (networkList != null) {
6742332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            if (DBG) Log.i(TAG, "Enable network and Set priorities for PNO.");
6752332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            for (WifiNative.PnoNetwork network : networkList) {
6762332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                if (!mWifiNative.setNetworkVariable(network.networkId,
6772332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                        WifiConfiguration.priorityVarName,
6782332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                        Integer.toString(network.priority))) {
6792332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    Log.e(TAG, "Set priority failed for: " + network.networkId);
6802332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    return false;
6812332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                }
68262bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius                if (!mWifiNative.enableNetworkWithoutConnect(network.networkId)) {
6832332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    Log.e(TAG, "Enable network failed for: " + network.networkId);
6842332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                    return false;
6852332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                }
6862332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            }
6872332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
6882332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        return true;
6892332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6902332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
69162bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius    private boolean startHwPnoScan() {
692e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        return mHwPnoDebouncer.startPnoScan(mHwPnoDebouncerListener);
6932332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6942332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
695e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    private void stopHwPnoScan() {
696e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        mHwPnoDebouncer.stopPnoScan();
6972332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
6982332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
699e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    private void pauseHwPnoScan() {
700e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        mHwPnoDebouncer.forceStopPnoScan();
7012332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
7022332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
7031bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius    private boolean restartHwPnoScan() {
7041bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius        mHwPnoDebouncer.forceStopPnoScan();
7051bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius        return mHwPnoDebouncer.startPnoScan(mHwPnoDebouncerListener);
7061bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius    }
7071bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius
708dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    /**
709dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * Hw Pno Scan is required only for disconnected PNO when the device supports it.
710dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * @param isConnectedPno Whether this is connected PNO vs disconnected PNO.
711dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     * @return true if HW PNO scan is required, false otherwise.
712dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius     */
713dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    private boolean isHwPnoScanRequired(boolean isConnectedPno) {
714dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        return (!isConnectedPno & mHwPnoScanSupported);
715dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    }
716dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius
717dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    private boolean isHwPnoScanRequired() {
718dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        if (mPnoSettings == null) return false;
719dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius        return isHwPnoScanRequired(mPnoSettings.isConnected);
720dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius    }
721dcd877d6c143db557884993ea437e2a432cb0ba3Roshan Pius
7222332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    @Override
7236c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius    public boolean setHwPnoList(WifiNative.PnoSettings settings,
7242332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            WifiNative.PnoEventHandler eventHandler) {
7252332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        synchronized (mSettingsLock) {
7262332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            if (mPnoSettings != null) {
7272332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                Log.w(TAG, "Already running a PNO scan");
7282332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                return false;
7292332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            }
7302332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoEventHandler = eventHandler;
7312332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoSettings = settings;
7326c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius            if (!setNetworkPriorities(settings.networkList)) return false;
7336c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius            // For supplicant based PNO, we start the scan immediately when we set pno list.
7346c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius            processPendingScans();
7352332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            return true;
7362332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
7372332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
7382332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
7392332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    @Override
740476172f2eef83ff367fae4344eda8129ea9d16f7Roshan Pius    public boolean resetHwPnoList() {
7412332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        synchronized (mSettingsLock) {
7422332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            if (mPnoSettings == null) {
7432332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                Log.w(TAG, "No PNO scan running");
7442332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius                return false;
7452332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            }
7462332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoEventHandler = null;
7472332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius            mPnoSettings = null;
7486c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius            // For supplicant based PNO, we stop the scan immediately when we reset pno list.
749e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            stopHwPnoScan();
750e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            return true;
7512332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius        }
7522332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
7532332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
7542332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    @Override
7556c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius    public boolean isHwPnoSupported(boolean isConnectedPno) {
7566c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius        // Hw Pno Scan is supported only for disconnected PNO when the device supports it.
7576c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius        return isHwPnoScanRequired(isConnectedPno);
7586c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius    }
7596c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius
7606c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius    @Override
7616c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius    public boolean shouldScheduleBackgroundScanForHwPno() {
7626c5018cef1eb7acbcfa7fc6c9b7c018bab7ba7baRoshan Pius        return false;
7632332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius    }
7642332e9ea1b691fa0ea3a340feec159f2040aa6caRoshan Pius
7659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
7669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public boolean setHotlist(WifiScanner.HotlistSettings settings,
7679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            WifiNative.HotlistEventHandler eventHandler) {
7689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        if (settings == null || eventHandler == null) {
7699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return false;
7709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7715fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
7729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = eventHandler;
7739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.setSettings(settings.bssidInfos, settings.apLostThreshold, 1);
7749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return true;
7759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
7779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
7789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    @Override
7799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    public void resetHotlist() {
7805fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        synchronized (mSettingsLock) {
7819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistChangeBuffer.clearSettings();
7829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mHotlistHandler = null;
7839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
7849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
7859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
78694bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    /*
78794bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills     * Significant Wifi Change API is not implemented
78894bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills     */
78994bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    @Override
79094bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    public boolean trackSignificantWifiChange(WifiScanner.WifiChangeSettings settings,
79194bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills            WifiNative.SignificantWifiChangeEventHandler handler) {
79294bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills        return false;
79394bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    }
79494bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    @Override
79594bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills    public void untrackSignificantWifiChange() {}
79694bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills
79794bd575cb4766ed0dfbaad0fc7719a9e9e85a260Mitchell Wills
7989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class LastScanSettings {
7995fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public long startTime;
8005fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
8015fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public LastScanSettings(long startTime) {
8025fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.startTime = startTime;
8035fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
8045fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
8055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        // Background settings
8065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean backgroundScanActive = false;
8075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int scanId;
8085fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int maxAps;
8095fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportEvents;
8105fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportNumScansThreshold;
8115fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int reportPercentThreshold;
8125fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
8135fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public void setBackgroundScan(int scanId, int maxAps, int reportEvents,
8149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int reportNumScansThreshold, int reportPercentThreshold) {
8155fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.backgroundScanActive = true;
8169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.scanId = scanId;
8179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.maxAps = maxAps;
8189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportEvents = reportEvents;
8199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportNumScansThreshold = reportNumScansThreshold;
8209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            this.reportPercentThreshold = reportPercentThreshold;
8219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8225fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
8235fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        // Single scan settings
8245fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean singleScanActive = false;
8255fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public boolean reportSingleScanFullResults;
8267e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills        public ChannelCollection singleScanFreqs;
8275fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public WifiNative.ScanEventHandler singleScanEventHandler;
8285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills
8295fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public void setSingleScan(boolean reportSingleScanFullResults,
8307e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                ChannelCollection singleScanFreqs,
8317e3e85327ca82a83de84b4750e793f2e3d1b3bfcMitchell Wills                WifiNative.ScanEventHandler singleScanEventHandler) {
8325fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            singleScanActive = true;
8335fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.reportSingleScanFullResults = reportSingleScanFullResults;
8345fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.singleScanFreqs = singleScanFreqs;
8355fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            this.singleScanEventHandler = singleScanEventHandler;
8365fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        }
837063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius
83862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        public boolean hwPnoScanActive = false;
8391bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius        public WifiNative.PnoNetwork[] pnoNetworkList;
840063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius        public WifiNative.PnoEventHandler pnoScanEventHandler;
841063cfc7e3eef78fcbda24a66f0c473828b39c854Roshan Pius
8421bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius        public void setHwPnoScan(
8431bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                WifiNative.PnoNetwork[] pnoNetworkList,
8441bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                WifiNative.PnoEventHandler pnoScanEventHandler) {
84562bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            hwPnoScanActive = true;
8461bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius            this.pnoNetworkList = pnoNetworkList;
84762bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius            this.pnoScanEventHandler = pnoScanEventHandler;
84862bc101940ae1f5e60c4d8861a149b900dbf5e5cRoshan Pius        }
8499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
8509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ScanBuffer {
8539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private final ArrayDeque<WifiScanner.ScanData> mBuffer;
8545fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        private int mCapacity;
8559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanBuffer(int capacity) {
8575fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mCapacity = capacity;
8585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            mBuffer = new ArrayDeque<>(mCapacity);
8599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int size() {
8629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.size();
8639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public int capacity() {
8665fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return mCapacity;
8679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public boolean isFull() {
8705fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            return size() == mCapacity;
8719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void add(WifiScanner.ScanData scanData) {
8749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (isFull()) {
8759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mBuffer.pollFirst();
8769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
8779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.offerLast(scanData);
8789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clear() {
8819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBuffer.clear();
8829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public WifiScanner.ScanData[] get() {
8859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return mBuffer.toArray(new WifiScanner.ScanData[mBuffer.size()]);
8869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
8879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
8889ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    private static class ChangeBuffer {
8909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_NONE = 0;
8919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_LOST = 1;
8929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public static int EVENT_FOUND = 2;
8939ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8945fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public static int STATE_FOUND = 0;
8959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
8969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private WifiScanner.BssidInfo[] mBssidInfos = null;
8979ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mApLostThreshold;
8989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int mMinEvents;
8999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mLostCount = null;
9009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private ScanResult[] mMostRecentResult = null;
9019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private int[] mPendingEvent = null;
9029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        private boolean mFiredEvents = false;
9039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9045fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        private static ScanResult findResult(List<ScanResult> results, String bssid) {
9055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            for (int i = 0; i < results.size(); ++i) {
9065fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                if (bssid.equalsIgnoreCase(results.get(i).BSSID)) {
9075fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    return results.get(i);
9089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return null;
9119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
9129ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void setSettings(WifiScanner.BssidInfo[] bssidInfos, int apLostThreshold,
9149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                int minEvents) {
9159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mBssidInfos = bssidInfos;
9169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (apLostThreshold <= 0) {
9179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = 1;
9185fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            } else {
9199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mApLostThreshold = apLostThreshold;
9209ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9219ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            mMinEvents = minEvents;
9229ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (bssidInfos != null) {
9239ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = new int[bssidInfos.length];
9249ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                Arrays.fill(mLostCount, mApLostThreshold); // default to lost
9259ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = new ScanResult[bssidInfos.length];
9269ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = new int[bssidInfos.length];
9279ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
9285fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            } else {
9299ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mLostCount = null;
9309ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mMostRecentResult = null;
9319ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mPendingEvent = null;
9329ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9339ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
9349ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9359ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public void clearSettings() {
9369ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            setSettings(null, 0, 0);
9379ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
9389ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9399ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
9409ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Get the most recent scan results for APs that triggered the given event on the last call
9419ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * to {@link #processScan}.
9429ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
9439ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        public ScanResult[] getLastResults(int event) {
9449ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            ArrayList<ScanResult> results = new ArrayList<>();
9459ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
9469ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] == event) {
9479ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    results.add(mMostRecentResult[i]);
9489ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9499ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9509ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return results.toArray(new ScanResult[results.size()]);
9519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
9529ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9539ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        /**
9549ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * Process the supplied scan results and determine if any events should be generated based
9559ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * on the configured settings
9569ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         * @return The events that occurred
9579ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills         */
9585fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills        public int processScan(List<ScanResult> scanResults) {
9599ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mBssidInfos == null) {
9609ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return EVENT_NONE;
9619ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9629ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9639ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            // clear events from last time
9649ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (mFiredEvents) {
9659ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = false;
9669ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                for (int i = 0; i < mLostCount.length; ++i) {
9679ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mPendingEvent[i] = EVENT_NONE;
9689ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9699ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
9709ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9719ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventCount = 0;
9729ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            int eventType = EVENT_NONE;
9739ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            for (int i = 0; i < mLostCount.length; ++i) {
9749ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                ScanResult result = findResult(scanResults, mBssidInfos[i].bssid);
9759ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                int rssi = Integer.MIN_VALUE;
9769ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (result != null) {
9779ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mMostRecentResult[i] = result;
9789ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    rssi = result.level;
9799ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
9809ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9819ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (rssi < mBssidInfos[i].low) {
9829ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] < mApLostThreshold) {
9839ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        mLostCount[i]++;
9849ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills
9859ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mLostCount[i] >= mApLostThreshold) {
9869ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            if (mPendingEvent[i] == EVENT_FOUND) {
9879ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_NONE;
9885fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            } else {
9899ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                                mPendingEvent[i] = EVENT_LOST;
9909ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            }
9919ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
9929ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
9935fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                } else {
9949ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    if (mLostCount[i] >= mApLostThreshold) {
9959ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        if (mPendingEvent[i] == EVENT_LOST) {
9969ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_NONE;
9975fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                        } else {
9989ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                            mPendingEvent[i] = EVENT_FOUND;
9999ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                        }
10009ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    }
10019ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    mLostCount[i] = STATE_FOUND;
10029ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
10039ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (DBG) {
10045fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                    Log.d(TAG, "ChangeBuffer BSSID: " + mBssidInfos[i].bssid + "=" + mLostCount[i]
10055fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills                            + ", " + mPendingEvent[i] + ", rssi=" + rssi);
10069ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
10079ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                if (mPendingEvent[i] != EVENT_NONE) {
10089ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    ++eventCount;
10099ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                    eventType |= mPendingEvent[i];
10109ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                }
10119ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
10125fa6221c4e507cbc596b6de77d793ec08d690157Mitchell Wills            if (DBG) Log.d(TAG, "ChangeBuffer events count=" + eventCount + ": " + eventType);
10139ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            if (eventCount >= mMinEvents) {
10149ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                mFiredEvents = true;
10159ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills                return eventType;
10169ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            }
10179ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills            return EVENT_NONE;
10189ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills        }
10199ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills    }
1020e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1021e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    /**
1022e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius     * HW PNO Debouncer is used to debounce PNO requests. This guards against toggling the PNO
1023e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius     * state too often which is not handled very well by some drivers.
1024e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius     * Note: This is not thread safe!
1025e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius     */
1026e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    public static class HwPnoDebouncer {
1027e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        public static final String PNO_DEBOUNCER_ALARM_TAG = TAG + "Pno Monitor";
1028e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private static final int MINIMUM_PNO_GAP_MS = 5 * 1000;
1029e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1030e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private final WifiNative mWifiNative;
1031e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private final AlarmManager mAlarmManager;
1032e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private final Handler mEventHandler;
1033ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        private final Clock mClock;
1034e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private long mLastPnoChangeTimeStamp = -1L;
1035e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private boolean mExpectedPnoState = false;
1036e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private boolean mCurrentPnoState = false;;
1037e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private boolean mWaitForTimer = false;
1038e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private Listener mListener;
1039e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1040e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        /**
1041e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * Interface used to indicate PNO scan notifications.
1042e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         */
1043e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        public interface Listener {
1044e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            /**
1045e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius             * Used to indicate a delayed PNO scan request failure.
1046e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius             */
1047e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            void onPnoScanFailed();
1048e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
1049e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1050e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        public HwPnoDebouncer(WifiNative wifiNative, AlarmManager alarmManager,
1051ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                Handler eventHandler, Clock clock) {
1052e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            mWifiNative = wifiNative;
1053e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            mAlarmManager = alarmManager;
1054e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            mEventHandler = eventHandler;
1055ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            mClock = clock;
1056e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
1057e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1058e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        /**
1059e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * Enable/Disable PNO state in wpa_supplicant
1060e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * @param enable boolean indicating whether PNO is being enabled or disabled.
1061e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         */
1062e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private boolean updatePnoState(boolean enable) {
1063e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            if (mCurrentPnoState == enable) {
1064e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                if (DBG) Log.d(TAG, "PNO state is already " + enable);
1065e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                return true;
1066e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            }
1067ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            mLastPnoChangeTimeStamp = mClock.elapsedRealtime();
1068e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            if (mWifiNative.setPnoScan(enable)) {
1069ab3adbcced14ec2ae5cf8f8a75f2ef9c9224f2a3Roshan Pius                Log.d(TAG, "Changed PNO state from " + mCurrentPnoState + " to " + enable);
1070e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                mCurrentPnoState = enable;
1071e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                return true;
1072e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            } else {
1073e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                Log.e(TAG, "PNO state change to " + enable + " failed");
1074e483fd4a3151e59b3d0a596572b4d9f035fa8424Roshan Pius                mCurrentPnoState = false;
1075e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                return false;
1076e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            }
1077e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
1078e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1079e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private final AlarmManager.OnAlarmListener mAlarmListener =
1080e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                new AlarmManager.OnAlarmListener() {
1081e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            public void onAlarm() {
1082e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                if (DBG) Log.d(TAG, "PNO timer expired, expected state " + mExpectedPnoState);
1083e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                if (!updatePnoState(mExpectedPnoState)) {
1084e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                    if (mListener != null) {
1085e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                        mListener.onPnoScanFailed();
1086e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                    }
1087e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                }
1088e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                mWaitForTimer = false;
1089e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            }
1090e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        };
1091e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1092e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        /**
1093e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * Enable/Disable PNO state. This method will debounce PNO scan requests.
1094e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * @param enable boolean indicating whether PNO is being enabled or disabled.
1095e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         */
1096e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        private boolean setPnoState(boolean enable) {
1097e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            boolean isSuccess = true;
1098e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            mExpectedPnoState = enable;
1099e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            if (!mWaitForTimer) {
1100ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                long timeDifference = mClock.elapsedRealtime() - mLastPnoChangeTimeStamp;
1101e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                if (timeDifference >= MINIMUM_PNO_GAP_MS) {
1102e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                    isSuccess = updatePnoState(enable);
1103e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                } else {
1104e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                    long alarmTimeout = MINIMUM_PNO_GAP_MS - timeDifference;
1105e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                    Log.d(TAG, "Start PNO timer with delay " + alarmTimeout);
1106ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1107ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                            mClock.elapsedRealtime() + alarmTimeout, PNO_DEBOUNCER_ALARM_TAG,
1108e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                            mAlarmListener, mEventHandler);
1109e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                    mWaitForTimer = true;
1110e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                }
1111e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            }
1112e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            return isSuccess;
1113e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
1114e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1115e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        /**
1116e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * Start PNO scan
1117e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         */
1118e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        public boolean startPnoScan(Listener listener) {
1119e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            if (DBG) Log.d(TAG, "Starting PNO scan");
1120e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            mListener = listener;
1121e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            if (!setPnoState(true)) {
1122e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                mListener = null;
1123e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius                return false;
1124e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            }
1125e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            return true;
1126e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
1127e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1128e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        /**
1129e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * Stop PNO scan
1130e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         */
1131e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        public void stopPnoScan() {
1132e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            if (DBG) Log.d(TAG, "Stopping PNO scan");
1133e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            setPnoState(false);
1134e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            mListener = null;
1135e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
1136e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius
1137e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        /**
1138e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * Force stop PNO scanning. This method will bypass the debounce logic and stop PNO
1139e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         * scan immediately.
1140e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius         */
1141e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        public void forceStopPnoScan() {
11421bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius            if (DBG) Log.d(TAG, "Force stopping Pno scan");
11431bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius            // Cancel the debounce timer and stop PNO scan.
11441bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius            if (mWaitForTimer) {
11451bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                mAlarmManager.cancel(mAlarmListener);
11461bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius                mWaitForTimer = false;
1147e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius            }
11481bf983a4211f547593a60523e43112ecdb5c8997Roshan Pius            updatePnoState(false);
1149e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius        }
1150e7ba2963bedf426a1d8ba09ab535260ef364512bRoshan Pius    }
11519ec71f6499e0e3d6f52310a41ff4a59d2fa4f8b2Mitchell Wills}
1152