WifiConnectivityManager.java revision 3d09b9117df33608a43c1fbe0135123e2de9aea2
184d962ec8f487f824214744498bba505a6db0c59Randy Pan/*
284d962ec8f487f824214744498bba505a6db0c59Randy Pan * Copyright (C) 2016 The Android Open Source Project
384d962ec8f487f824214744498bba505a6db0c59Randy Pan *
484d962ec8f487f824214744498bba505a6db0c59Randy Pan * Licensed under the Apache License, Version 2.0 (the "License");
584d962ec8f487f824214744498bba505a6db0c59Randy Pan * you may not use this file except in compliance with the License.
684d962ec8f487f824214744498bba505a6db0c59Randy Pan * You may obtain a copy of the License at
784d962ec8f487f824214744498bba505a6db0c59Randy Pan *
884d962ec8f487f824214744498bba505a6db0c59Randy Pan *      http://www.apache.org/licenses/LICENSE-2.0
984d962ec8f487f824214744498bba505a6db0c59Randy Pan *
1084d962ec8f487f824214744498bba505a6db0c59Randy Pan * Unless required by applicable law or agreed to in writing, software
1184d962ec8f487f824214744498bba505a6db0c59Randy Pan * distributed under the License is distributed on an "AS IS" BASIS,
1284d962ec8f487f824214744498bba505a6db0c59Randy Pan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1384d962ec8f487f824214744498bba505a6db0c59Randy Pan * See the License for the specific language governing permissions and
1484d962ec8f487f824214744498bba505a6db0c59Randy Pan * limitations under the License.
1584d962ec8f487f824214744498bba505a6db0c59Randy Pan */
1684d962ec8f487f824214744498bba505a6db0c59Randy Pan
1784d962ec8f487f824214744498bba505a6db0c59Randy Panpackage com.android.server.wifi;
1884d962ec8f487f824214744498bba505a6db0c59Randy Pan
1948444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Willsimport static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE;
2048444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Wills
2184d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.app.ActivityManager;
2284d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.app.AlarmManager;
2384d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.content.Context;
2484d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.ScanResult;
25eeb1a3c3cb4c09f925496000392d63b2b28301f7Randy Panimport android.net.wifi.SupplicantState;
2684d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiConfiguration;
2784d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiInfo;
2884d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiManager;
2984d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiScanner;
3084d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiScanner.PnoSettings;
3184d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiScanner.ScanSettings;
32c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Panimport android.os.Handler;
33c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Panimport android.os.Looper;
3484d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.util.LocalLog;
3584d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.util.Log;
3684d962ec8f487f824214744498bba505a6db0c59Randy Pan
3784d962ec8f487f824214744498bba505a6db0c59Randy Panimport com.android.internal.R;
383d09b9117df33608a43c1fbe0135123e2de9aea2Randy Panimport com.android.internal.annotations.VisibleForTesting;
3984d962ec8f487f824214744498bba505a6db0c59Randy Panimport com.android.server.wifi.util.ScanDetailUtil;
4084d962ec8f487f824214744498bba505a6db0c59Randy Pan
4184d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.io.FileDescriptor;
4284d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.io.PrintWriter;
4384d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.util.ArrayList;
444f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Piusimport java.util.Iterator;
454f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Piusimport java.util.LinkedList;
4684d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.util.List;
4784d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.util.Set;
4884d962ec8f487f824214744498bba505a6db0c59Randy Pan
4984d962ec8f487f824214744498bba505a6db0c59Randy Pan/**
5084d962ec8f487f824214744498bba505a6db0c59Randy Pan * This class manages all the connectivity related scanning activities.
5184d962ec8f487f824214744498bba505a6db0c59Randy Pan *
5284d962ec8f487f824214744498bba505a6db0c59Randy Pan * When the screen is turned on or off, WiFi is connected or disconnected,
5384d962ec8f487f824214744498bba505a6db0c59Randy Pan * or on-demand, a scan is initiatiated and the scan results are passed
5484d962ec8f487f824214744498bba505a6db0c59Randy Pan * to QNS for it to make a recommendation on which network to connect to.
5584d962ec8f487f824214744498bba505a6db0c59Randy Pan */
5684d962ec8f487f824214744498bba505a6db0c59Randy Panpublic class WifiConnectivityManager {
5784d962ec8f487f824214744498bba505a6db0c59Randy Pan    private static final String TAG = "WifiConnectivityManager";
5884d962ec8f487f824214744498bba505a6db0c59Randy Pan
5984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Periodic scan interval in milli-seconds. This is the scan
6084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // performed when screen is on.
614f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int PERIODIC_SCAN_INTERVAL_MS = 20 * 1000; // 20 seconds
6284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // PNO scan interval in milli-seconds. This is the scan
6379e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // performed when screen is off and disconnected.
644f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int DISCONNECTED_PNO_SCAN_INTERVAL_MS = 20 * 1000; // 20 seconds
6579e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // PNO scan interval in milli-seconds. This is the scan
6679e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // performed when screen is off and connected.
674f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int CONNECTED_PNO_SCAN_INTERVAL_MS = 160 * 1000; // 160 seconds
683d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // When a network is found by PNO scan but gets rejected by QNS due to its
693d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // low RSSI value, scan will be reschduled in an exponential back off manner.
703d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private static final int LOW_RSSI_NETWORK_RETRY_START_DELAY_MS = 20 * 1000; // 20 seconds
713d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private static final int LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS = 80 * 1000; // 80 seconds
7284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Maximum number of retries when starting a scan failed
7384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private static final int MAX_SCAN_RESTART_ALLOWED = 5;
7484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Number of milli-seconds to delay before retry starting
7584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // a previously failed scan
764f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int RESTART_SCAN_DELAY_MS = 2 * 1000; // 2 seconds
7784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // When in disconnected mode, a watchdog timer will be fired
7884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // every WATCHDOG_INTERVAL_MS to start a single scan. This is
7984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // to prevent caveat from things like PNO scan.
804f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int WATCHDOG_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes
814f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    // This is the time interval for the connection attempt rate calculation. Connection attempt
824f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    // timestamps beyond this interval is evicted from the list.
83fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    public static final int MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS = 4 * 60 * 1000; // 4 mins
844f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    // Max number of connection attempts in the above time interval.
85fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    public static final int MAX_CONNECTION_ATTEMPTS_RATE = 6;
8684d962ec8f487f824214744498bba505a6db0c59Randy Pan
8784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // WifiStateMachine has a bunch of states. From the
8884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // WifiConnectivityManager's perspective it only cares
8984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if it is in Connected state, Disconnected state or in
9084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // transition between these two states.
9184d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_UNKNOWN = 0;
9284d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_CONNECTED = 1;
9384d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_DISCONNECTED = 2;
9484d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_TRANSITIONING = 3;
9584d962ec8f487f824214744498bba505a6db0c59Randy Pan
9679e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // Due to b/28020168, timer based single scan will be scheduled every
9779e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan.
987ce0f144104c68da40c196c16f73e2d0bcc50cc7Roshan Pius    private static final boolean ENABLE_BACKGROUND_SCAN = false;
9979e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // Flag to turn on connected PNO, when needed
1007ce0f144104c68da40c196c16f73e2d0bcc50cc7Roshan Pius    private static final boolean ENABLE_CONNECTED_PNO_SCAN = false;
10179e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius
10284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiStateMachine mStateMachine;
10384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiScanner mScanner;
10484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiConfigManager mConfigManager;
10584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiInfo mWifiInfo;
10684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiQualifiedNetworkSelector mQualifiedNetworkSelector;
10709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    private final WifiLastResortWatchdog mWifiLastResortWatchdog;
108fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    private final AlarmManager mAlarmManager;
109c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan    private final Handler mEventHandler;
110fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    private final Clock mClock;
111fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    private final LocalLog mLocalLog =
112fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 1024 : 16384);
1134f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private final LinkedList<Long> mConnectionAttemptTimeStamps;
114fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
11584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mDbg = false;
11684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mWifiEnabled = false;
117466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    private boolean mWifiConnectivityManagerEnabled = true;
11884d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mForceSelectNetwork = false;
11984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mScreenOn = false;
12084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mWifiState = WIFI_STATE_UNKNOWN;
12184d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mUntrustedConnectionAllowed = false;
12284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mScanRestartCount = 0;
12384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mSingleScanRestartCount = 0;
124d54ddacc42d9cd929d40b1df391895293bacafe2Roshan Pius    private int mTotalConnectivityAttemptsRateLimited = 0;
12584d962ec8f487f824214744498bba505a6db0c59Randy Pan
12684d962ec8f487f824214744498bba505a6db0c59Randy Pan    // PNO settings
12784d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mMin5GHzRssi;
12884d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mMin24GHzRssi;
12984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mInitialScoreMax;
13084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mCurrentConnectionBonus;
13184d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mSameNetworkBonus;
13284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mSecureBonus;
13384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mBand5GHzBonus;
13484d962ec8f487f824214744498bba505a6db0c59Randy Pan
13584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A helper to log debugging information in the local log buffer, which can
13684d962ec8f487f824214744498bba505a6db0c59Randy Pan    // be retrieved in bugreport.
13784d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void localLog(String log) {
13884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mLocalLog.log(log);
13984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
14084d962ec8f487f824214744498bba505a6db0c59Randy Pan
14184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A periodic/PNO scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times
14284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if the start scan command failed. An timer is used here to make it a deferred retry.
14384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final AlarmManager.OnAlarmListener mRestartScanListener =
14484d962ec8f487f824214744498bba505a6db0c59Randy Pan            new AlarmManager.OnAlarmListener() {
14584d962ec8f487f824214744498bba505a6db0c59Randy Pan                public void onAlarm() {
14684d962ec8f487f824214744498bba505a6db0c59Randy Pan                    startConnectivityScan(mForceSelectNetwork);
14784d962ec8f487f824214744498bba505a6db0c59Randy Pan                }
14884d962ec8f487f824214744498bba505a6db0c59Randy Pan            };
14984d962ec8f487f824214744498bba505a6db0c59Randy Pan
15084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A single scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times
15184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if the start scan command failed. An timer is used here to make it a deferred retry.
15284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final AlarmManager.OnAlarmListener mRestartSingleScanListener =
15384d962ec8f487f824214744498bba505a6db0c59Randy Pan            new AlarmManager.OnAlarmListener() {
15484d962ec8f487f824214744498bba505a6db0c59Randy Pan                public void onAlarm() {
15584d962ec8f487f824214744498bba505a6db0c59Randy Pan                    startSingleScan();
15684d962ec8f487f824214744498bba505a6db0c59Randy Pan                }
15784d962ec8f487f824214744498bba505a6db0c59Randy Pan            };
15884d962ec8f487f824214744498bba505a6db0c59Randy Pan
15984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // As a watchdog mechanism, a single scan will be scheduled every WATCHDOG_INTERVAL_MS
16084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if it is in the WIFI_STATE_DISCONNECTED state.
16184d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final AlarmManager.OnAlarmListener mWatchdogListener =
16284d962ec8f487f824214744498bba505a6db0c59Randy Pan            new AlarmManager.OnAlarmListener() {
16384d962ec8f487f824214744498bba505a6db0c59Randy Pan                public void onAlarm() {
16484d962ec8f487f824214744498bba505a6db0c59Randy Pan                    watchdogHandler();
16584d962ec8f487f824214744498bba505a6db0c59Randy Pan                }
16684d962ec8f487f824214744498bba505a6db0c59Randy Pan            };
16784d962ec8f487f824214744498bba505a6db0c59Randy Pan
16884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Due to b/28020168, timer based single scan will be scheduled every
16984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan.
17084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final AlarmManager.OnAlarmListener mPeriodicScanTimerListener =
17184d962ec8f487f824214744498bba505a6db0c59Randy Pan            new AlarmManager.OnAlarmListener() {
17284d962ec8f487f824214744498bba505a6db0c59Randy Pan                public void onAlarm() {
17384d962ec8f487f824214744498bba505a6db0c59Randy Pan                    periodicScanTimerHandler();
17484d962ec8f487f824214744498bba505a6db0c59Randy Pan                }
17584d962ec8f487f824214744498bba505a6db0c59Randy Pan            };
17684d962ec8f487f824214744498bba505a6db0c59Randy Pan
17709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    /**
17809abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     * Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.
17909abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     * Executes selection of potential network candidates, initiation of connection attempt to that
18009abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     * network.
1813d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     *
1823d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     * @return true - if a candidate is selected by QNS
1833d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     *         false - if no candidate is selected by QNS
18409abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     */
1853d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {
18609abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        localLog(listenerName + " onResults: start QNS");
18709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        WifiConfiguration candidate =
18809abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mQualifiedNetworkSelector.selectQualifiedNetwork(mForceSelectNetwork,
18909abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mUntrustedConnectionAllowed, scanDetails,
19009abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(),
19109abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mStateMachine.isDisconnected(),
19209abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mStateMachine.isSupplicantTransientState());
19309abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiLastResortWatchdog.updateAvailableNetworks(
19409abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mQualifiedNetworkSelector.getFilteredScanDetails());
19509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        if (candidate != null) {
19609abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne            localLog(listenerName + ": QNS candidate-" + candidate.SSID);
19709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne            connectToNetwork(candidate);
1983d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            return true;
1993d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        } else {
2003d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            return false;
20109abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        }
20209abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    }
20309abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne
20484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Periodic scan results listener. A periodic scan is initiated when
20584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // screen is on.
20684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private class PeriodicScanListener implements WifiScanner.ScanListener {
20784d962ec8f487f824214744498bba505a6db0c59Randy Pan        private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
20884d962ec8f487f824214744498bba505a6db0c59Randy Pan
20984d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void clearScanDetails() {
21084d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.clear();
21184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
21284d962ec8f487f824214744498bba505a6db0c59Randy Pan
21384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
21484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onSuccess() {
21584d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PeriodicScanListener onSuccess");
21684d962ec8f487f824214744498bba505a6db0c59Randy Pan
21784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reset the count
21884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanRestartCount = 0;
21984d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
22084d962ec8f487f824214744498bba505a6db0c59Randy Pan
22184d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
22284d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFailure(int reason, String description) {
22384d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "PeriodicScanListener onFailure:"
22484d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " reason: " + reason
22584d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " description: " + description);
22684d962ec8f487f824214744498bba505a6db0c59Randy Pan
22784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reschedule the scan
22884d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
2293d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                scheduleDelayedConnectivityScan(RESTART_SCAN_DELAY_MS);
23084d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
23184d962ec8f487f824214744498bba505a6db0c59Randy Pan                mScanRestartCount = 0;
23284d962ec8f487f824214744498bba505a6db0c59Randy Pan                Log.e(TAG, "Failed to successfully start periodic scan for "
23384d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + MAX_SCAN_RESTART_ALLOWED + " times");
23484d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
23584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
23684d962ec8f487f824214744498bba505a6db0c59Randy Pan
23784d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
23884d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPeriodChanged(int periodInMs) {
23984d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PeriodicScanListener onPeriodChanged: "
24084d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + "actual scan period " + periodInMs + "ms");
24184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
24284d962ec8f487f824214744498bba505a6db0c59Randy Pan
24384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
24484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onResults(WifiScanner.ScanData[] results) {
24509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne            handleScanResults(mScanDetails, "PeriodicScanListener");
24684d962ec8f487f824214744498bba505a6db0c59Randy Pan            clearScanDetails();
24784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
24884d962ec8f487f824214744498bba505a6db0c59Randy Pan
24984d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
25084d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFullResult(ScanResult fullScanResult) {
25184d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mDbg) {
25284d962ec8f487f824214744498bba505a6db0c59Randy Pan                localLog("PeriodicScanListener onFullResult: "
25384d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.SSID + " capabilities "
25484d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.capabilities);
25584d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
25684d962ec8f487f824214744498bba505a6db0c59Randy Pan
25784d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult));
25884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
25984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
26084d962ec8f487f824214744498bba505a6db0c59Randy Pan
26184d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final PeriodicScanListener mPeriodicScanListener = new PeriodicScanListener();
26284d962ec8f487f824214744498bba505a6db0c59Randy Pan
26384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Single scan results listener. A single scan is initiated when
26484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Disconnected/ConnectedPNO scan found a valid network and woke up
26584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // the system, or by the watchdog timer.
26684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private class SingleScanListener implements WifiScanner.ScanListener {
26784d962ec8f487f824214744498bba505a6db0c59Randy Pan        private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
26884d962ec8f487f824214744498bba505a6db0c59Randy Pan
26984d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void clearScanDetails() {
27084d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.clear();
27184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
27284d962ec8f487f824214744498bba505a6db0c59Randy Pan
27384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
27484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onSuccess() {
27584d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("SingleScanListener onSuccess");
27684d962ec8f487f824214744498bba505a6db0c59Randy Pan
27784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reset the count
27884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mSingleScanRestartCount = 0;
27984d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
28084d962ec8f487f824214744498bba505a6db0c59Randy Pan
28184d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
28284d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFailure(int reason, String description) {
28384d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "SingleScanListener onFailure:"
28484d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " reason: " + reason
28584d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " description: " + description);
28684d962ec8f487f824214744498bba505a6db0c59Randy Pan
28784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reschedule the scan
28884d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mSingleScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
28984d962ec8f487f824214744498bba505a6db0c59Randy Pan                scheduleDelayedSingleScan();
29084d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
29184d962ec8f487f824214744498bba505a6db0c59Randy Pan                mSingleScanRestartCount = 0;
29284d962ec8f487f824214744498bba505a6db0c59Randy Pan                Log.e(TAG, "Failed to successfully start single scan for "
29384d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + MAX_SCAN_RESTART_ALLOWED + " times");
29484d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
29584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
29684d962ec8f487f824214744498bba505a6db0c59Randy Pan
29784d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
29884d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPeriodChanged(int periodInMs) {
29984d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("SingleScanListener onPeriodChanged: "
30084d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + "actual scan period " + periodInMs + "ms");
30184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
30284d962ec8f487f824214744498bba505a6db0c59Randy Pan
30384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
30484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onResults(WifiScanner.ScanData[] results) {
30509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne            handleScanResults(mScanDetails, "SingleScanListener");
306224198c8ba46f362a5df6d25f1b60e56f442b58bRoshan Pius            clearScanDetails();
30784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
30884d962ec8f487f824214744498bba505a6db0c59Randy Pan
30984d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
31084d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFullResult(ScanResult fullScanResult) {
31184d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mDbg) {
31284d962ec8f487f824214744498bba505a6db0c59Randy Pan                localLog("SingleScanListener onFullResult: "
31384d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.SSID + " capabilities "
31484d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.capabilities);
31584d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
31684d962ec8f487f824214744498bba505a6db0c59Randy Pan
31784d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult));
31884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
31984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
32084d962ec8f487f824214744498bba505a6db0c59Randy Pan
32184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // re-enable this when b/27695292 is fixed
32284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // private final SingleScanListener mSingleScanListener = new SingleScanListener();
32384d962ec8f487f824214744498bba505a6db0c59Randy Pan
32484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // PNO scan results listener for both disconected and connected PNO scanning.
32584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A PNO scan is initiated when screen is off.
32684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private class PnoScanListener implements WifiScanner.PnoScanListener {
32784d962ec8f487f824214744498bba505a6db0c59Randy Pan        private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
3283d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        private int mLowRssiNetworkRetryDelay =
3293d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                LOW_RSSI_NETWORK_RETRY_START_DELAY_MS;
33084d962ec8f487f824214744498bba505a6db0c59Randy Pan
33184d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void clearScanDetails() {
33284d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.clear();
33384d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
33484d962ec8f487f824214744498bba505a6db0c59Randy Pan
3353d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // Reset to the start value when either a non-PNO scan is started or
3363d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // QNS selects a candidate from the PNO scan results.
3373d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        public void resetLowRssiNetworkRetryDelay() {
3383d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_START_DELAY_MS;
3393d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        }
3403d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
3413d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        @VisibleForTesting
3423d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        public int getLowRssiNetworkRetryDelay() {
3433d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            return mLowRssiNetworkRetryDelay;
3443d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        }
3453d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
34684d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
34784d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onSuccess() {
34884d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PnoScanListener onSuccess");
34984d962ec8f487f824214744498bba505a6db0c59Randy Pan
35084d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reset the count
35184d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanRestartCount = 0;
35284d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
35384d962ec8f487f824214744498bba505a6db0c59Randy Pan
35484d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
35584d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFailure(int reason, String description) {
35684d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "PnoScanListener onFailure:"
35784d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " reason: " + reason
35884d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " description: " + description);
35984d962ec8f487f824214744498bba505a6db0c59Randy Pan
36084d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reschedule the scan
36184d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
3623d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                scheduleDelayedConnectivityScan(RESTART_SCAN_DELAY_MS);
36384d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
36484d962ec8f487f824214744498bba505a6db0c59Randy Pan                mScanRestartCount = 0;
36584d962ec8f487f824214744498bba505a6db0c59Randy Pan                Log.e(TAG, "Failed to successfully start PNO scan for "
36684d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + MAX_SCAN_RESTART_ALLOWED + " times");
36784d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
36884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
36984d962ec8f487f824214744498bba505a6db0c59Randy Pan
37084d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
37184d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPeriodChanged(int periodInMs) {
37284d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PnoScanListener onPeriodChanged: "
37384d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + "actual scan period " + periodInMs + "ms");
37484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
37584d962ec8f487f824214744498bba505a6db0c59Randy Pan
37684d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Currently the PNO scan results doesn't include IE,
37784d962ec8f487f824214744498bba505a6db0c59Randy Pan        // which contains information required by QNS. Ignore them
37884d962ec8f487f824214744498bba505a6db0c59Randy Pan        // for now.
37984d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
38084d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onResults(WifiScanner.ScanData[] results) {
38184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
38284d962ec8f487f824214744498bba505a6db0c59Randy Pan
38384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
38484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFullResult(ScanResult fullScanResult) {
38584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
38684d962ec8f487f824214744498bba505a6db0c59Randy Pan
38784d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
38884d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPnoNetworkFound(ScanResult[] results) {
38984d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PnoScanListener: onPnoNetworkFound: results len = " + results.length);
39084d962ec8f487f824214744498bba505a6db0c59Randy Pan
39184d962ec8f487f824214744498bba505a6db0c59Randy Pan            for (ScanResult result: results) {
39284d962ec8f487f824214744498bba505a6db0c59Randy Pan                mScanDetails.add(ScanDetailUtil.toScanDetail(result));
39384d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
3943d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
3953d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            boolean wasConnectAttempted;
3963d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            wasConnectAttempted = handleScanResults(mScanDetails, "PnoScanListener");
397224198c8ba46f362a5df6d25f1b60e56f442b58bRoshan Pius            clearScanDetails();
3983d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
3993d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            if (!wasConnectAttempted) {
4003d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                // The scan results were rejected by QNS due to low RSSI values
4013d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                if (mLowRssiNetworkRetryDelay > LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS) {
4023d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                    mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS;
4033d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                }
4043d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                scheduleDelayedConnectivityScan(mLowRssiNetworkRetryDelay);
4053d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
4063d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                // Set up the delay value for next retry.
4073d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                mLowRssiNetworkRetryDelay *= 2;
4083d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            } else {
4093d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                resetLowRssiNetworkRetryDelay();
4103d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            }
41184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
41284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
41384d962ec8f487f824214744498bba505a6db0c59Randy Pan
41484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final PnoScanListener mPnoScanListener = new PnoScanListener();
41584d962ec8f487f824214744498bba505a6db0c59Randy Pan
41684d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
41784d962ec8f487f824214744498bba505a6db0c59Randy Pan     * WifiConnectivityManager constructor
41884d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
41984d962ec8f487f824214744498bba505a6db0c59Randy Pan    public WifiConnectivityManager(Context context, WifiStateMachine stateMachine,
42084d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,
42109abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                WifiQualifiedNetworkSelector qualifiedNetworkSelector,
422c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                WifiInjector wifiInjector, Looper looper) {
42384d962ec8f487f824214744498bba505a6db0c59Randy Pan        mStateMachine = stateMachine;
42484d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanner = scanner;
42584d962ec8f487f824214744498bba505a6db0c59Randy Pan        mConfigManager = configManager;
42684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiInfo = wifiInfo;
427fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mQualifiedNetworkSelector = qualifiedNetworkSelector;
42809abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog();
429fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
430c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan        mEventHandler = new Handler(looper);
431fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mClock = wifiInjector.getClock();
4324f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        mConnectionAttemptTimeStamps = new LinkedList<>();
43384d962ec8f487f824214744498bba505a6db0c59Randy Pan
43484d962ec8f487f824214744498bba505a6db0c59Randy Pan        mMin5GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI;
43584d962ec8f487f824214744498bba505a6db0c59Randy Pan        mMin24GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI;
43684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mBand5GHzBonus = WifiQualifiedNetworkSelector.BAND_AWARD_5GHz;
43773a52d3336a40903965b946f6d3624a223ad5aacSamuel Tan        mCurrentConnectionBonus = mConfigManager.mCurrentNetworkBoost.get();
43884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mSameNetworkBonus = context.getResources().getInteger(
43984d962ec8f487f824214744498bba505a6db0c59Randy Pan                                R.integer.config_wifi_framework_SAME_BSSID_AWARD);
44084d962ec8f487f824214744498bba505a6db0c59Randy Pan        mSecureBonus = context.getResources().getInteger(
44184d962ec8f487f824214744498bba505a6db0c59Randy Pan                            R.integer.config_wifi_framework_SECURITY_AWARD);
44273a52d3336a40903965b946f6d3624a223ad5aacSamuel Tan        mInitialScoreMax = (mConfigManager.mThresholdSaturatedRssi24.get()
44384d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + WifiQualifiedNetworkSelector.RSSI_SCORE_OFFSET)
44484d962ec8f487f824214744498bba505a6db0c59Randy Pan                            * WifiQualifiedNetworkSelector.RSSI_SCORE_SLOPE;
44584d962ec8f487f824214744498bba505a6db0c59Randy Pan
44684d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "PNO settings:" + " min5GHzRssi " + mMin5GHzRssi
44784d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " min24GHzRssi " + mMin24GHzRssi
44884d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " currentConnectionBonus " + mCurrentConnectionBonus
44984d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " sameNetworkBonus " + mSameNetworkBonus
45084d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " secureNetworkBonus " + mSecureBonus
45184d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " initialScoreMax " + mInitialScoreMax);
45284d962ec8f487f824214744498bba505a6db0c59Randy Pan
45384d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "ConnectivityScanManager initialized ");
45484d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
45584d962ec8f487f824214744498bba505a6db0c59Randy Pan
45684d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
4574f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * This checks the connection attempt rate and recommends whether the connection attempt
4584f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * should be skipped or not. This attempts to rate limit the rate of connections to
4594f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * prevent us from flapping between networks and draining battery rapidly.
4604f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     */
4614f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private boolean shouldSkipConnectionAttempt(Long currentTimeMillis) {
4624f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        Iterator<Long> attemptIter = mConnectionAttemptTimeStamps.iterator();
4634f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        // First evict old entries from the queue.
464c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan        while (attemptIter.hasNext()) {
4654f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            Long connectionAttemptTimeMillis = attemptIter.next();
466c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan            if ((currentTimeMillis - connectionAttemptTimeMillis)
467c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                    > MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS) {
4684f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius                attemptIter.remove();
4694f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            } else {
4704f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius                // This list is sorted by timestamps, so we can skip any more checks
4714f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius                break;
4724f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            }
4734f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        }
4744f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        // If we've reached the max connection attempt rate, skip this connection attempt
4754f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        return (mConnectionAttemptTimeStamps.size() >= MAX_CONNECTION_ATTEMPTS_RATE);
4764f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    }
4774f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
4784f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    /**
4794f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * Add the current connection attempt timestamp to our queue of connection attempts.
4804f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     */
4814f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private void noteConnectionAttempt(Long currentTimeMillis) {
4824f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        mConnectionAttemptTimeStamps.addLast(currentTimeMillis);
4834f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    }
4844f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
4854f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    /**
4864f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * This is used to clear the connection attempt rate limiter. This is done when the user
4874f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * explicitly tries to connect to a specified network.
4884f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     */
4894f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private void clearConnectionAttemptTimeStamps() {
4904f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        mConnectionAttemptTimeStamps.clear();
4914f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    }
4924f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
4934f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    /**
49484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Attempt to connect to a network candidate.
49584d962ec8f487f824214744498bba505a6db0c59Randy Pan     *
49684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Based on the currently connected network, this menthod determines whether we should
49784d962ec8f487f824214744498bba505a6db0c59Randy Pan     * connect or roam to the network candidate recommended by QNS.
49884d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
49984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void connectToNetwork(WifiConfiguration candidate) {
50084d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();
50184d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (scanResultCandidate == null) {
50284d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "connectToNetwork: bad candidate - "  + candidate
50384d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " scanResult: " + scanResultCandidate);
50484d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
50584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
50684d962ec8f487f824214744498bba505a6db0c59Randy Pan
50784d962ec8f487f824214744498bba505a6db0c59Randy Pan        String targetBssid = scanResultCandidate.BSSID;
50884d962ec8f487f824214744498bba505a6db0c59Randy Pan        String targetAssociationId = candidate.SSID + " : " + targetBssid;
509eeb1a3c3cb4c09f925496000392d63b2b28301f7Randy Pan        if (targetBssid != null && targetBssid.equals(mWifiInfo.getBSSID())
510eeb1a3c3cb4c09f925496000392d63b2b28301f7Randy Pan                    && SupplicantState.isConnecting(mWifiInfo.getSupplicantState())) {
511eeb1a3c3cb4c09f925496000392d63b2b28301f7Randy Pan            localLog("connectToNetwork: Either already connected "
512eeb1a3c3cb4c09f925496000392d63b2b28301f7Randy Pan                    + "or is connecting to " + targetAssociationId);
51384d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
51484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
51584d962ec8f487f824214744498bba505a6db0c59Randy Pan
516fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        Long currentTimeMillis = mClock.currentTimeMillis();
5174f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        if (!mScreenOn && shouldSkipConnectionAttempt(currentTimeMillis)) {
5184f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            localLog("connectToNetwork: Too many connection attempts. Skipping this attempt!");
519d54ddacc42d9cd929d40b1df391895293bacafe2Roshan Pius            mTotalConnectivityAttemptsRateLimited++;
5204f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            return;
5214f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        }
5224f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        noteConnectionAttempt(currentTimeMillis);
5234f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
52484d962ec8f487f824214744498bba505a6db0c59Randy Pan        WifiConfiguration currentConnectedNetwork = mConfigManager
52584d962ec8f487f824214744498bba505a6db0c59Randy Pan                .getWifiConfiguration(mWifiInfo.getNetworkId());
52684d962ec8f487f824214744498bba505a6db0c59Randy Pan        String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" :
52784d962ec8f487f824214744498bba505a6db0c59Randy Pan                (mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID());
52884d962ec8f487f824214744498bba505a6db0c59Randy Pan
52984d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (currentConnectedNetwork != null
53084d962ec8f487f824214744498bba505a6db0c59Randy Pan                && (currentConnectedNetwork.networkId == candidate.networkId
53184d962ec8f487f824214744498bba505a6db0c59Randy Pan                || currentConnectedNetwork.isLinked(candidate))) {
53284d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("connectToNetwork: Roaming from " + currentAssociationId + " to "
53384d962ec8f487f824214744498bba505a6db0c59Randy Pan                        + targetAssociationId);
53484d962ec8f487f824214744498bba505a6db0c59Randy Pan            mStateMachine.autoRoamToNetwork(candidate.networkId, scanResultCandidate);
53584d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
53684d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("connectToNetwork: Reconnect from " + currentAssociationId + " to "
53784d962ec8f487f824214744498bba505a6db0c59Randy Pan                        + targetAssociationId);
53884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mStateMachine.autoConnectToNetwork(candidate.networkId, scanResultCandidate.BSSID);
53984d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
54084d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
54184d962ec8f487f824214744498bba505a6db0c59Randy Pan
54284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Helper for selecting the band for connectivity scan
54384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int getScanBand() {
54484d962ec8f487f824214744498bba505a6db0c59Randy Pan        int freqBand = mStateMachine.getFrequencyBand();
54584d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_5GHZ) {
54684d962ec8f487f824214744498bba505a6db0c59Randy Pan            return WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS;
54784d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_2GHZ) {
54884d962ec8f487f824214744498bba505a6db0c59Randy Pan            return WifiScanner.WIFI_BAND_24_GHZ;
54984d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
55084d962ec8f487f824214744498bba505a6db0c59Randy Pan            return WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
55184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
55284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
55384d962ec8f487f824214744498bba505a6db0c59Randy Pan
55484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Watchdog timer handler
55584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void watchdogHandler() {
55684d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("watchdogHandler");
55784d962ec8f487f824214744498bba505a6db0c59Randy Pan
55884d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Schedule the next timer and start a single scan if we are in disconnected state.
55984d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Otherwise, the watchdog timer will be scheduled when entering disconnected
56084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // state.
56184d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mWifiState == WIFI_STATE_DISCONNECTED) {
56284d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.i(TAG, "start a single scan from watchdogHandler");
56384d962ec8f487f824214744498bba505a6db0c59Randy Pan
56484d962ec8f487f824214744498bba505a6db0c59Randy Pan            scheduleWatchdogTimer();
56584d962ec8f487f824214744498bba505a6db0c59Randy Pan            startSingleScan();
56684d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
56784d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
56884d962ec8f487f824214744498bba505a6db0c59Randy Pan
56984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Periodic scan timer handler
57084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void periodicScanTimerHandler() {
57184d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("periodicScanTimerHandler");
57284d962ec8f487f824214744498bba505a6db0c59Randy Pan
57384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Schedule the next timer and start a single scan if screen is on.
57484d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mScreenOn) {
57584d962ec8f487f824214744498bba505a6db0c59Randy Pan            schedulePeriodicScanTimer();
57684d962ec8f487f824214744498bba505a6db0c59Randy Pan            startSingleScan();
57784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
57884d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
57984d962ec8f487f824214744498bba505a6db0c59Randy Pan
5803d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // Start a single scan
58184d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void startSingleScan() {
582466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
58384d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
58484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
58584d962ec8f487f824214744498bba505a6db0c59Randy Pan
5863d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        mPnoScanListener.resetLowRssiNetworkRetryDelay();
5873d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
58884d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanSettings settings = new ScanSettings();
58984d962ec8f487f824214744498bba505a6db0c59Randy Pan        settings.band = getScanBand();
59084d962ec8f487f824214744498bba505a6db0c59Randy Pan        settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
59184d962ec8f487f824214744498bba505a6db0c59Randy Pan                            | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
59284d962ec8f487f824214744498bba505a6db0c59Randy Pan        settings.numBssidsPerScan = 0;
59384d962ec8f487f824214744498bba505a6db0c59Randy Pan
59484d962ec8f487f824214744498bba505a6db0c59Randy Pan        //Retrieve the list of hidden networkId's to scan for.
59584d962ec8f487f824214744498bba505a6db0c59Randy Pan        Set<Integer> hiddenNetworkIds = mConfigManager.getHiddenConfiguredNetworkIds();
59684d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (hiddenNetworkIds != null && hiddenNetworkIds.size() > 0) {
59784d962ec8f487f824214744498bba505a6db0c59Randy Pan            int i = 0;
59884d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.hiddenNetworkIds = new int[hiddenNetworkIds.size()];
59984d962ec8f487f824214744498bba505a6db0c59Randy Pan            for (Integer netId : hiddenNetworkIds) {
60084d962ec8f487f824214744498bba505a6db0c59Randy Pan                settings.hiddenNetworkIds[i++] = netId;
60184d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
60284d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
60384d962ec8f487f824214744498bba505a6db0c59Randy Pan
60484d962ec8f487f824214744498bba505a6db0c59Randy Pan        // re-enable this when b/27695292 is fixed
60584d962ec8f487f824214744498bba505a6db0c59Randy Pan        // mSingleScanListener.clearScanDetails();
60648444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Wills        // mScanner.startScan(settings, mSingleScanListener, WIFI_WORK_SOURCE);
60784d962ec8f487f824214744498bba505a6db0c59Randy Pan        SingleScanListener singleScanListener = new SingleScanListener();
60848444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Wills        mScanner.startScan(settings, singleScanListener, WIFI_WORK_SOURCE);
60984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
61084d962ec8f487f824214744498bba505a6db0c59Randy Pan
61184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a periodic scan when screen is on
61284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void startPeriodicScan() {
6133d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        mPnoScanListener.resetLowRssiNetworkRetryDelay();
6143d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
61584d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Due to b/28020168, timer based single scan will be scheduled every
61684d962ec8f487f824214744498bba505a6db0c59Randy Pan        // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan.
61779e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        if (!ENABLE_BACKGROUND_SCAN) {
61884d962ec8f487f824214744498bba505a6db0c59Randy Pan            startSingleScan();
61984d962ec8f487f824214744498bba505a6db0c59Randy Pan            schedulePeriodicScanTimer();
62084d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
62184d962ec8f487f824214744498bba505a6db0c59Randy Pan            ScanSettings settings = new ScanSettings();
62284d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.band = getScanBand();
62384d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
62484d962ec8f487f824214744498bba505a6db0c59Randy Pan                                | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
62584d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.numBssidsPerScan = 0;
62684d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.periodInMs = PERIODIC_SCAN_INTERVAL_MS;
62784d962ec8f487f824214744498bba505a6db0c59Randy Pan
62884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mPeriodicScanListener.clearScanDetails();
62948444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Wills            mScanner.startBackgroundScan(settings, mPeriodicScanListener, WIFI_WORK_SOURCE);
63084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
63184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
63284d962ec8f487f824214744498bba505a6db0c59Randy Pan
63384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a DisconnectedPNO scan when screen is off and Wifi is disconnected
63484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void startDisconnectedPnoScan() {
63584d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize PNO settings
63684d962ec8f487f824214744498bba505a6db0c59Randy Pan        PnoSettings pnoSettings = new PnoSettings();
63784d962ec8f487f824214744498bba505a6db0c59Randy Pan        ArrayList<PnoSettings.PnoNetwork> pnoNetworkList =
638329b3a9a9bc32d14649e91c15876ea7f95f148d1Roshan Pius                mConfigManager.retrieveDisconnectedPnoNetworkList();
63984d962ec8f487f824214744498bba505a6db0c59Randy Pan        int listSize = pnoNetworkList.size();
64084d962ec8f487f824214744498bba505a6db0c59Randy Pan
64184d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (listSize == 0) {
64284d962ec8f487f824214744498bba505a6db0c59Randy Pan            // No saved network
64384d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("No saved network for starting disconnected PNO.");
64484d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
64584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
64684d962ec8f487f824214744498bba505a6db0c59Randy Pan
64784d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize];
64884d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList);
64984d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min5GHzRssi = mMin5GHzRssi;
65084d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min24GHzRssi = mMin24GHzRssi;
65184d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.initialScoreMax = mInitialScoreMax;
65284d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.currentConnectionBonus = mCurrentConnectionBonus;
65384d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.sameNetworkBonus = mSameNetworkBonus;
65484d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.secureBonus = mSecureBonus;
65584d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.band5GHzBonus = mBand5GHzBonus;
65684d962ec8f487f824214744498bba505a6db0c59Randy Pan
65784d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize scan settings
65884d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanSettings scanSettings = new ScanSettings();
65984d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.band = getScanBand();
66084d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH;
66184d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.numBssidsPerScan = 0;
66279e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        scanSettings.periodInMs = DISCONNECTED_PNO_SCAN_INTERVAL_MS;
66384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // TODO: enable exponential back off scan later to further save energy
66484d962ec8f487f824214744498bba505a6db0c59Randy Pan        // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs;
66584d962ec8f487f824214744498bba505a6db0c59Randy Pan
66684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mPnoScanListener.clearScanDetails();
66784d962ec8f487f824214744498bba505a6db0c59Randy Pan
66884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener);
66984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
67084d962ec8f487f824214744498bba505a6db0c59Randy Pan
67184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a ConnectedPNO scan when screen is off and Wifi is connected
67284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void startConnectedPnoScan() {
67384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Disable ConnectedPNO for now due to b/28020168
67479e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        if (!ENABLE_CONNECTED_PNO_SCAN) {
67584d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
67684d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
67784d962ec8f487f824214744498bba505a6db0c59Randy Pan
67884d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize PNO settings
67984d962ec8f487f824214744498bba505a6db0c59Randy Pan        PnoSettings pnoSettings = new PnoSettings();
68084d962ec8f487f824214744498bba505a6db0c59Randy Pan        ArrayList<PnoSettings.PnoNetwork> pnoNetworkList =
68184d962ec8f487f824214744498bba505a6db0c59Randy Pan                mConfigManager.retrieveConnectedPnoNetworkList();
68284d962ec8f487f824214744498bba505a6db0c59Randy Pan        int listSize = pnoNetworkList.size();
68384d962ec8f487f824214744498bba505a6db0c59Randy Pan
68484d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (listSize == 0) {
68584d962ec8f487f824214744498bba505a6db0c59Randy Pan            // No saved network
68684d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("No saved network for starting connected PNO.");
68784d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
68884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
68984d962ec8f487f824214744498bba505a6db0c59Randy Pan
69084d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize];
69184d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList);
69284d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min5GHzRssi = mMin5GHzRssi;
69384d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min24GHzRssi = mMin24GHzRssi;
69484d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.initialScoreMax = mInitialScoreMax;
69584d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.currentConnectionBonus = mCurrentConnectionBonus;
69684d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.sameNetworkBonus = mSameNetworkBonus;
69784d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.secureBonus = mSecureBonus;
69884d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.band5GHzBonus = mBand5GHzBonus;
69984d962ec8f487f824214744498bba505a6db0c59Randy Pan
70084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize scan settings
70184d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanSettings scanSettings = new ScanSettings();
70284d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.band = getScanBand();
70384d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH;
70484d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.numBssidsPerScan = 0;
70579e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        scanSettings.periodInMs = CONNECTED_PNO_SCAN_INTERVAL_MS;
70684d962ec8f487f824214744498bba505a6db0c59Randy Pan        // TODO: enable exponential back off scan later to further save energy
70784d962ec8f487f824214744498bba505a6db0c59Randy Pan        // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs;
70884d962ec8f487f824214744498bba505a6db0c59Randy Pan
70984d962ec8f487f824214744498bba505a6db0c59Randy Pan        mPnoScanListener.clearScanDetails();
71084d962ec8f487f824214744498bba505a6db0c59Randy Pan
71184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanner.startConnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener);
71284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
71384d962ec8f487f824214744498bba505a6db0c59Randy Pan
71484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Set up watchdog timer
71584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void scheduleWatchdogTimer() {
71684d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "scheduleWatchdogTimer");
71784d962ec8f487f824214744498bba505a6db0c59Randy Pan
71884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
719fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                            mClock.currentTimeMillis() + WATCHDOG_INTERVAL_MS,
72084d962ec8f487f824214744498bba505a6db0c59Randy Pan                            "WifiConnectivityManager Schedule Watchdog Timer",
721c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                            mWatchdogListener, mEventHandler);
72284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
72384d962ec8f487f824214744498bba505a6db0c59Randy Pan
72484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Set up periodic scan timer
72584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void schedulePeriodicScanTimer() {
72684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
727fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                            mClock.currentTimeMillis() + PERIODIC_SCAN_INTERVAL_MS,
72884d962ec8f487f824214744498bba505a6db0c59Randy Pan                            "WifiConnectivityManager Schedule Periodic Scan Timer",
729c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                            mPeriodicScanTimerListener, mEventHandler);
73084d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
73184d962ec8f487f824214744498bba505a6db0c59Randy Pan
73284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Set up timer to start a delayed single scan after RESTART_SCAN_DELAY_MS
73384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void scheduleDelayedSingleScan() {
73484d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("scheduleDelayedSingleScan");
73584d962ec8f487f824214744498bba505a6db0c59Randy Pan
73684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
737fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                            mClock.currentTimeMillis() + RESTART_SCAN_DELAY_MS,
73884d962ec8f487f824214744498bba505a6db0c59Randy Pan                            "WifiConnectivityManager Restart Single Scan",
739c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                            mRestartSingleScanListener, mEventHandler);
74084d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
74184d962ec8f487f824214744498bba505a6db0c59Randy Pan
7423d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // Set up timer to start a delayed scan after msFromNow milli-seconds
7433d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private void scheduleDelayedConnectivityScan(int msFromNow) {
74484d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("scheduleDelayedConnectivityScan");
74584d962ec8f487f824214744498bba505a6db0c59Randy Pan
74684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
7473d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                            mClock.currentTimeMillis() + msFromNow,
74884d962ec8f487f824214744498bba505a6db0c59Randy Pan                            "WifiConnectivityManager Restart Scan",
749c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                            mRestartScanListener, mEventHandler);
75084d962ec8f487f824214744498bba505a6db0c59Randy Pan
75184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
75284d962ec8f487f824214744498bba505a6db0c59Randy Pan
75384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a connectivity scan. The scan method is chosen according to
75484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // the current screen state and WiFi state.
75584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void startConnectivityScan(boolean forceSelectNetwork) {
75684d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("startConnectivityScan: screenOn=" + mScreenOn
75784d962ec8f487f824214744498bba505a6db0c59Randy Pan                        + " wifiState=" + mWifiState
75884d962ec8f487f824214744498bba505a6db0c59Randy Pan                        + " forceSelectNetwork=" + forceSelectNetwork
759466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan                        + " wifiEnabled=" + mWifiEnabled
760466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan                        + " wifiConnectivityManagerEnabled="
761466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan                        + mWifiConnectivityManagerEnabled);
76284d962ec8f487f824214744498bba505a6db0c59Randy Pan
763466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
76484d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
76584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
76684d962ec8f487f824214744498bba505a6db0c59Randy Pan
76784d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Always stop outstanding connecivity scan if there is any
76884d962ec8f487f824214744498bba505a6db0c59Randy Pan        stopConnectivityScan();
76984d962ec8f487f824214744498bba505a6db0c59Randy Pan
77084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Don't start a connectivity scan while Wifi is in the transition
77184d962ec8f487f824214744498bba505a6db0c59Randy Pan        // between connected and disconnected states.
77284d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mWifiState != WIFI_STATE_CONNECTED && mWifiState != WIFI_STATE_DISCONNECTED) {
77384d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
77484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
77584d962ec8f487f824214744498bba505a6db0c59Randy Pan
77684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mForceSelectNetwork = forceSelectNetwork;
77784d962ec8f487f824214744498bba505a6db0c59Randy Pan
77884d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mScreenOn) {
77984d962ec8f487f824214744498bba505a6db0c59Randy Pan            startPeriodicScan();
78084d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else { // screenOff
78184d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mWifiState == WIFI_STATE_CONNECTED) {
78284d962ec8f487f824214744498bba505a6db0c59Randy Pan                startConnectedPnoScan();
78384d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
78484d962ec8f487f824214744498bba505a6db0c59Randy Pan                startDisconnectedPnoScan();
78584d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
78684d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
78784d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
78884d962ec8f487f824214744498bba505a6db0c59Randy Pan
78984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Stop connectivity scan if there is any.
79084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void stopConnectivityScan() {
79184d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Due to b/28020168, timer based single scan will be scheduled every
79284d962ec8f487f824214744498bba505a6db0c59Randy Pan        // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan.
79379e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        if (!ENABLE_BACKGROUND_SCAN) {
79484d962ec8f487f824214744498bba505a6db0c59Randy Pan            mAlarmManager.cancel(mPeriodicScanTimerListener);
79584d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
79684d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanner.stopBackgroundScan(mPeriodicScanListener);
79784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
798f37079e3d8f4aca3242a971cbaef732fe1b75bdeRoshan Pius        mScanner.stopPnoScan(mPnoScanListener);
79984d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanRestartCount = 0;
80084d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
80184d962ec8f487f824214744498bba505a6db0c59Randy Pan
80284d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
80384d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler for screen state (on/off) changes
80484d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
80584d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void handleScreenStateChanged(boolean screenOn) {
80684d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("handleScreenStateChanged: screenOn=" + screenOn);
80784d962ec8f487f824214744498bba505a6db0c59Randy Pan
80884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScreenOn = screenOn;
80984d962ec8f487f824214744498bba505a6db0c59Randy Pan
81084d962ec8f487f824214744498bba505a6db0c59Randy Pan        startConnectivityScan(false);
81184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
81284d962ec8f487f824214744498bba505a6db0c59Randy Pan
81384d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
81484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler for WiFi state (connected/disconnected) changes
81584d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
81684d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void handleConnectionStateChanged(int state) {
81784d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("handleConnectionStateChanged: state=" + state);
81884d962ec8f487f824214744498bba505a6db0c59Randy Pan
81984d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiState = state;
82084d962ec8f487f824214744498bba505a6db0c59Randy Pan
82184d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Kick off the watchdog timer if entering disconnected state
82284d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mWifiState == WIFI_STATE_DISCONNECTED) {
82384d962ec8f487f824214744498bba505a6db0c59Randy Pan            scheduleWatchdogTimer();
82484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
82584d962ec8f487f824214744498bba505a6db0c59Randy Pan
82684d962ec8f487f824214744498bba505a6db0c59Randy Pan        startConnectivityScan(false);
82784d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
82884d962ec8f487f824214744498bba505a6db0c59Randy Pan
82984d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
83084d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler when user toggles whether untrusted connection is allowed
83184d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
83284d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void setUntrustedConnectionAllowed(boolean allowed) {
83384d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "setUntrustedConnectionAllowed: allowed=" + allowed);
83484d962ec8f487f824214744498bba505a6db0c59Randy Pan
83584d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mUntrustedConnectionAllowed != allowed) {
83684d962ec8f487f824214744498bba505a6db0c59Randy Pan            mUntrustedConnectionAllowed = allowed;
83784d962ec8f487f824214744498bba505a6db0c59Randy Pan            startConnectivityScan(false);
83884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
83984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
84084d962ec8f487f824214744498bba505a6db0c59Randy Pan
84184d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
84284d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler when user specifies a particular network to connect to
84384d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
84484d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void connectToUserSelectNetwork(int netId, boolean persistent) {
84584d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "connectToUserSelectNetwork: netId=" + netId
84684d962ec8f487f824214744498bba505a6db0c59Randy Pan                   + " persist=" + persistent);
84784d962ec8f487f824214744498bba505a6db0c59Randy Pan
84884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mQualifiedNetworkSelector.userSelectNetwork(netId, persistent);
84984d962ec8f487f824214744498bba505a6db0c59Randy Pan
8504f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        clearConnectionAttemptTimeStamps();
8514f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
85284d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initiate a scan which will trigger the connection to the user selected
85384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // network when scan result is available.
85484d962ec8f487f824214744498bba505a6db0c59Randy Pan        startConnectivityScan(true);
85584d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
85684d962ec8f487f824214744498bba505a6db0c59Randy Pan
85784d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
85884d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler for on-demand connectivity scan
85984d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
86084d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void forceConnectivityScan() {
86184d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "forceConnectivityScan");
86284d962ec8f487f824214744498bba505a6db0c59Randy Pan
86384d962ec8f487f824214744498bba505a6db0c59Randy Pan        startConnectivityScan(false);
86484d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
86584d962ec8f487f824214744498bba505a6db0c59Randy Pan
86684d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
86784d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Track whether a BSSID should be enabled or disabled for QNS
86884d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
86984d962ec8f487f824214744498bba505a6db0c59Randy Pan    public boolean trackBssid(String bssid, boolean enable) {
87084d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "trackBssid: " + (enable ? "enable " : "disable ") + bssid);
87184d962ec8f487f824214744498bba505a6db0c59Randy Pan
87284d962ec8f487f824214744498bba505a6db0c59Randy Pan        boolean ret = mQualifiedNetworkSelector
87384d962ec8f487f824214744498bba505a6db0c59Randy Pan                            .enableBssidForQualityNetworkSelection(bssid, enable);
87484d962ec8f487f824214744498bba505a6db0c59Randy Pan
87584d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (ret && !enable) {
87684d962ec8f487f824214744498bba505a6db0c59Randy Pan            // Disabling a BSSID can happen when the AP candidate to connect to has
87784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // no capacity for new stations. We start another scan immediately so that QNS
87884d962ec8f487f824214744498bba505a6db0c59Randy Pan            // can give us another candidate to connect to.
87984d962ec8f487f824214744498bba505a6db0c59Randy Pan            startConnectivityScan(false);
88084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
88184d962ec8f487f824214744498bba505a6db0c59Randy Pan
88284d962ec8f487f824214744498bba505a6db0c59Randy Pan        return ret;
88384d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
88484d962ec8f487f824214744498bba505a6db0c59Randy Pan
88584d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
88684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Set band preference when doing scan and making connection
88784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
88884d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void setUserPreferredBand(int band) {
88984d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "User band preference: " + band);
89084d962ec8f487f824214744498bba505a6db0c59Randy Pan
89184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mQualifiedNetworkSelector.setUserPreferredBand(band);
89284d962ec8f487f824214744498bba505a6db0c59Randy Pan        startConnectivityScan(false);
89384d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
89484d962ec8f487f824214744498bba505a6db0c59Randy Pan
89584d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
89684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Inform WiFi is enabled for connection or not
89784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
89884d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void setWifiEnabled(boolean enable) {
89984d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "Set WiFi " + (enable ? "enabled" : "disabled"));
90084d962ec8f487f824214744498bba505a6db0c59Randy Pan
90184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiEnabled = enable;
90284d962ec8f487f824214744498bba505a6db0c59Randy Pan
90384d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (!mWifiEnabled) {
90484d962ec8f487f824214744498bba505a6db0c59Randy Pan            stopConnectivityScan();
90584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
90684d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
90784d962ec8f487f824214744498bba505a6db0c59Randy Pan
90884d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
909466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan     * Turn on/off the WifiConnectivityMangager at runtime
910466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan     */
911466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    public void enable(boolean enable) {
912466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        Log.i(TAG, "Set WiFiConnectivityManager " + (enable ? "enabled" : "disabled"));
913466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan
914466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        mWifiConnectivityManagerEnabled = enable;
915466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan
916466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        if (!mWifiConnectivityManagerEnabled) {
917466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan            stopConnectivityScan();
918466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        }
919466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    }
920466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan
921466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    /**
92284d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Enable/disable verbose logging
92384d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
92484d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void enableVerboseLogging(int verbose) {
92584d962ec8f487f824214744498bba505a6db0c59Randy Pan        mDbg = verbose > 0;
92684d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
92784d962ec8f487f824214744498bba505a6db0c59Randy Pan
92884d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
92984d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Dump the local log buffer
93084d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
93184d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
93284d962ec8f487f824214744498bba505a6db0c59Randy Pan        pw.println("Dump of WifiConnectivityManager");
93384d962ec8f487f824214744498bba505a6db0c59Randy Pan        pw.println("WifiConnectivityManager - Log Begin ----");
9343d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        pw.println("WifiConnectivityManager - Number of connectivity attempts rate limited: "
9353d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                + mTotalConnectivityAttemptsRateLimited);
93684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mLocalLog.dump(fd, pw, args);
93784d962ec8f487f824214744498bba505a6db0c59Randy Pan        pw.println("WifiConnectivityManager - Log End ----");
93884d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
9393d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
9403d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    @VisibleForTesting
9413d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    int getLowRssiNetworkRetryDelay() {
9423d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        return mPnoScanListener.getLowRssiNetworkRetryDelay();
9433d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    }
94484d962ec8f487f824214744498bba505a6db0c59Randy Pan}
945