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;
44ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Panimport java.util.HashSet;
454f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Piusimport java.util.Iterator;
464f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Piusimport java.util.LinkedList;
4784d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.util.List;
4884d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.util.Set;
4984d962ec8f487f824214744498bba505a6db0c59Randy Pan
5084d962ec8f487f824214744498bba505a6db0c59Randy Pan/**
5184d962ec8f487f824214744498bba505a6db0c59Randy Pan * This class manages all the connectivity related scanning activities.
5284d962ec8f487f824214744498bba505a6db0c59Randy Pan *
5384d962ec8f487f824214744498bba505a6db0c59Randy Pan * When the screen is turned on or off, WiFi is connected or disconnected,
5484d962ec8f487f824214744498bba505a6db0c59Randy Pan * or on-demand, a scan is initiatiated and the scan results are passed
5584d962ec8f487f824214744498bba505a6db0c59Randy Pan * to QNS for it to make a recommendation on which network to connect to.
5684d962ec8f487f824214744498bba505a6db0c59Randy Pan */
5784d962ec8f487f824214744498bba505a6db0c59Randy Panpublic class WifiConnectivityManager {
581d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    public static final String WATCHDOG_TIMER_TAG =
591d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius            "WifiConnectivityManager Schedule Watchdog Timer";
601d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    public static final String PERIODIC_SCAN_TIMER_TAG =
611d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius            "WifiConnectivityManager Schedule Periodic Scan Timer";
621d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    public static final String RESTART_SINGLE_SCAN_TIMER_TAG =
631d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius            "WifiConnectivityManager Restart Single Scan";
641d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    public static final String RESTART_CONNECTIVITY_SCAN_TIMER_TAG =
651d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius            "WifiConnectivityManager Restart Scan";
6684d962ec8f487f824214744498bba505a6db0c59Randy Pan
671d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    private static final String TAG = "WifiConnectivityManager";
68016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
69016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    // Constants to indicate whether a scan should start immediately or
70016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    // it should comply to the minimum scan interval rule.
71016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    private static final boolean SCAN_IMMEDIATELY = true;
72016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    private static final boolean SCAN_ON_SCHEDULE = false;
7384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Periodic scan interval in milli-seconds. This is the scan
7484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // performed when screen is on.
75b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    @VisibleForTesting
76b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    public static final int PERIODIC_SCAN_INTERVAL_MS = 20 * 1000; // 20 seconds
77ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // When screen is on and WiFi traffic is heavy, exponential backoff
78ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // connectivity scans are scheduled. This constant defines the maximum
79ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // scan interval in this scenario.
80b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    @VisibleForTesting
81b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    public static final int MAX_PERIODIC_SCAN_INTERVAL_MS = 160 * 1000; // 160 seconds
8284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // PNO scan interval in milli-seconds. This is the scan
8379e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // performed when screen is off and disconnected.
844f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int DISCONNECTED_PNO_SCAN_INTERVAL_MS = 20 * 1000; // 20 seconds
8579e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // PNO scan interval in milli-seconds. This is the scan
8679e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // performed when screen is off and connected.
874f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int CONNECTED_PNO_SCAN_INTERVAL_MS = 160 * 1000; // 160 seconds
883d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // When a network is found by PNO scan but gets rejected by QNS due to its
893d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // low RSSI value, scan will be reschduled in an exponential back off manner.
903d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private static final int LOW_RSSI_NETWORK_RETRY_START_DELAY_MS = 20 * 1000; // 20 seconds
913d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private static final int LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS = 80 * 1000; // 80 seconds
9284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Maximum number of retries when starting a scan failed
9384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private static final int MAX_SCAN_RESTART_ALLOWED = 5;
9484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Number of milli-seconds to delay before retry starting
9584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // a previously failed scan
964f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int RESTART_SCAN_DELAY_MS = 2 * 1000; // 2 seconds
9784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // When in disconnected mode, a watchdog timer will be fired
9884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // every WATCHDOG_INTERVAL_MS to start a single scan. This is
9984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // to prevent caveat from things like PNO scan.
1004f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private static final int WATCHDOG_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes
101ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // Restricted channel list age out value.
102ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    private static final int CHANNEL_LIST_AGE_MS = 60 * 60 * 1000; // 1 hour
1034f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    // This is the time interval for the connection attempt rate calculation. Connection attempt
1044f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    // timestamps beyond this interval is evicted from the list.
105fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    public static final int MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS = 4 * 60 * 1000; // 4 mins
1064f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    // Max number of connection attempts in the above time interval.
107fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    public static final int MAX_CONNECTION_ATTEMPTS_RATE = 6;
10884d962ec8f487f824214744498bba505a6db0c59Randy Pan
10984d962ec8f487f824214744498bba505a6db0c59Randy Pan    // WifiStateMachine has a bunch of states. From the
11084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // WifiConnectivityManager's perspective it only cares
11184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if it is in Connected state, Disconnected state or in
11284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // transition between these two states.
11384d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_UNKNOWN = 0;
11484d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_CONNECTED = 1;
11584d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_DISCONNECTED = 2;
11684d962ec8f487f824214744498bba505a6db0c59Randy Pan    public static final int WIFI_STATE_TRANSITIONING = 3;
11784d962ec8f487f824214744498bba505a6db0c59Randy Pan
118ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // Due to b/28020168, timer based single scan will be scheduled
119ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // to provide periodic scan in an exponential backoff fashion.
1207ce0f144104c68da40c196c16f73e2d0bcc50cc7Roshan Pius    private static final boolean ENABLE_BACKGROUND_SCAN = false;
12179e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius    // Flag to turn on connected PNO, when needed
1227ce0f144104c68da40c196c16f73e2d0bcc50cc7Roshan Pius    private static final boolean ENABLE_CONNECTED_PNO_SCAN = false;
12379e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius
12484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiStateMachine mStateMachine;
12584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiScanner mScanner;
12684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiConfigManager mConfigManager;
12784d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiInfo mWifiInfo;
12884d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final WifiQualifiedNetworkSelector mQualifiedNetworkSelector;
12909abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    private final WifiLastResortWatchdog mWifiLastResortWatchdog;
130bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius    private final WifiMetrics mWifiMetrics;
131fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    private final AlarmManager mAlarmManager;
132c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan    private final Handler mEventHandler;
133fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    private final Clock mClock;
134fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    private final LocalLog mLocalLog =
13515941215e85f924765f00779e9b5daff9ed6f118Randy Pan            new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 256 : 1024);
1364f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private final LinkedList<Long> mConnectionAttemptTimeStamps;
137fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
13884d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mDbg = false;
13984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mWifiEnabled = false;
140466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    private boolean mWifiConnectivityManagerEnabled = true;
14184d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mScreenOn = false;
14284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mWifiState = WIFI_STATE_UNKNOWN;
14384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private boolean mUntrustedConnectionAllowed = false;
14484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mScanRestartCount = 0;
14584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mSingleScanRestartCount = 0;
146d54ddacc42d9cd929d40b1df391895293bacafe2Roshan Pius    private int mTotalConnectivityAttemptsRateLimited = 0;
14750abba06efa7834b5309df561375e4a2e2df630dRandy Pan    private String mLastConnectionAttemptBssid = null;
148ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    private int mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
149016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    private long mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP;
15084d962ec8f487f824214744498bba505a6db0c59Randy Pan
15184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // PNO settings
15284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mMin5GHzRssi;
15384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mMin24GHzRssi;
15484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mInitialScoreMax;
15584d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mCurrentConnectionBonus;
15684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mSameNetworkBonus;
15784d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mSecureBonus;
15884d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int mBand5GHzBonus;
15984d962ec8f487f824214744498bba505a6db0c59Randy Pan
16084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A helper to log debugging information in the local log buffer, which can
16184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // be retrieved in bugreport.
16284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void localLog(String log) {
16384d962ec8f487f824214744498bba505a6db0c59Randy Pan        mLocalLog.log(log);
16484d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
16584d962ec8f487f824214744498bba505a6db0c59Randy Pan
16684d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A periodic/PNO scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times
16784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if the start scan command failed. An timer is used here to make it a deferred retry.
16884d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final AlarmManager.OnAlarmListener mRestartScanListener =
16984d962ec8f487f824214744498bba505a6db0c59Randy Pan            new AlarmManager.OnAlarmListener() {
17084d962ec8f487f824214744498bba505a6db0c59Randy Pan                public void onAlarm() {
171016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan                    startConnectivityScan(SCAN_IMMEDIATELY);
17284d962ec8f487f824214744498bba505a6db0c59Randy Pan                }
17384d962ec8f487f824214744498bba505a6db0c59Randy Pan            };
17484d962ec8f487f824214744498bba505a6db0c59Randy Pan
17584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A single scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times
17684d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if the start scan command failed. An timer is used here to make it a deferred retry.
177bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius    private class RestartSingleScanListener implements AlarmManager.OnAlarmListener {
178bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        private final boolean mIsWatchdogTriggered;
179ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        private final boolean mIsFullBandScan;
180bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius
181304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan        RestartSingleScanListener(boolean isWatchdogTriggered, boolean isFullBandScan) {
182bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius            mIsWatchdogTriggered = isWatchdogTriggered;
183ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            mIsFullBandScan = isFullBandScan;
184bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        }
185bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius
186bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        @Override
187bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        public void onAlarm() {
188304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan            startSingleScan(mIsWatchdogTriggered, mIsFullBandScan);
189bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        }
190bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius    }
19184d962ec8f487f824214744498bba505a6db0c59Randy Pan
19284d962ec8f487f824214744498bba505a6db0c59Randy Pan    // As a watchdog mechanism, a single scan will be scheduled every WATCHDOG_INTERVAL_MS
19384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // if it is in the WIFI_STATE_DISCONNECTED state.
19484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final AlarmManager.OnAlarmListener mWatchdogListener =
19584d962ec8f487f824214744498bba505a6db0c59Randy Pan            new AlarmManager.OnAlarmListener() {
19684d962ec8f487f824214744498bba505a6db0c59Randy Pan                public void onAlarm() {
19784d962ec8f487f824214744498bba505a6db0c59Randy Pan                    watchdogHandler();
19884d962ec8f487f824214744498bba505a6db0c59Randy Pan                }
19984d962ec8f487f824214744498bba505a6db0c59Randy Pan            };
20084d962ec8f487f824214744498bba505a6db0c59Randy Pan
201ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // Due to b/28020168, timer based single scan will be scheduled
202ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // to provide periodic scan in an exponential backoff fashion.
20384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final AlarmManager.OnAlarmListener mPeriodicScanTimerListener =
20484d962ec8f487f824214744498bba505a6db0c59Randy Pan            new AlarmManager.OnAlarmListener() {
20584d962ec8f487f824214744498bba505a6db0c59Randy Pan                public void onAlarm() {
20684d962ec8f487f824214744498bba505a6db0c59Randy Pan                    periodicScanTimerHandler();
20784d962ec8f487f824214744498bba505a6db0c59Randy Pan                }
20884d962ec8f487f824214744498bba505a6db0c59Randy Pan            };
20984d962ec8f487f824214744498bba505a6db0c59Randy Pan
21009abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    /**
21109abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     * Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.
21209abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     * Executes selection of potential network candidates, initiation of connection attempt to that
21309abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     * network.
2143d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     *
2153d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     * @return true - if a candidate is selected by QNS
2163d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     *         false - if no candidate is selected by QNS
21709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne     */
2183d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {
21909abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        localLog(listenerName + " onResults: start QNS");
22009abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        WifiConfiguration candidate =
221016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan                mQualifiedNetworkSelector.selectQualifiedNetwork(false,
22209abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mUntrustedConnectionAllowed, scanDetails,
22309abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(),
22409abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mStateMachine.isDisconnected(),
22509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mStateMachine.isSupplicantTransientState());
22609abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiLastResortWatchdog.updateAvailableNetworks(
22709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                mQualifiedNetworkSelector.getFilteredScanDetails());
22809abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        if (candidate != null) {
22909abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne            localLog(listenerName + ": QNS candidate-" + candidate.SSID);
23009abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne            connectToNetwork(candidate);
2313d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            return true;
2323d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        } else {
2333d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            return false;
23409abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        }
23509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    }
23609abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne
23784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Periodic scan results listener. A periodic scan is initiated when
23884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // screen is on.
23984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private class PeriodicScanListener implements WifiScanner.ScanListener {
24084d962ec8f487f824214744498bba505a6db0c59Randy Pan        private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
24184d962ec8f487f824214744498bba505a6db0c59Randy Pan
24284d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void clearScanDetails() {
24384d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.clear();
24484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
24584d962ec8f487f824214744498bba505a6db0c59Randy Pan
24684d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
24784d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onSuccess() {
24884d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PeriodicScanListener onSuccess");
24984d962ec8f487f824214744498bba505a6db0c59Randy Pan
25084d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reset the count
25184d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanRestartCount = 0;
25284d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
25384d962ec8f487f824214744498bba505a6db0c59Randy Pan
25484d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
25584d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFailure(int reason, String description) {
25684d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "PeriodicScanListener onFailure:"
25784d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " reason: " + reason
25884d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " description: " + description);
25984d962ec8f487f824214744498bba505a6db0c59Randy Pan
26084d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reschedule the scan
26184d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
2623d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                scheduleDelayedConnectivityScan(RESTART_SCAN_DELAY_MS);
26384d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
26484d962ec8f487f824214744498bba505a6db0c59Randy Pan                mScanRestartCount = 0;
26584d962ec8f487f824214744498bba505a6db0c59Randy Pan                Log.e(TAG, "Failed to successfully start periodic scan for "
26684d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + MAX_SCAN_RESTART_ALLOWED + " times");
26784d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
26884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
26984d962ec8f487f824214744498bba505a6db0c59Randy Pan
27084d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
27184d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPeriodChanged(int periodInMs) {
27284d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PeriodicScanListener onPeriodChanged: "
27384d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + "actual scan period " + periodInMs + "ms");
27484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
27584d962ec8f487f824214744498bba505a6db0c59Randy Pan
27684d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
27784d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onResults(WifiScanner.ScanData[] results) {
27809abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne            handleScanResults(mScanDetails, "PeriodicScanListener");
27984d962ec8f487f824214744498bba505a6db0c59Randy Pan            clearScanDetails();
28084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
28184d962ec8f487f824214744498bba505a6db0c59Randy Pan
28284d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
28384d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFullResult(ScanResult fullScanResult) {
28484d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mDbg) {
28584d962ec8f487f824214744498bba505a6db0c59Randy Pan                localLog("PeriodicScanListener onFullResult: "
28684d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.SSID + " capabilities "
28784d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.capabilities);
28884d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
28984d962ec8f487f824214744498bba505a6db0c59Randy Pan
29084d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult));
29184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
29284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
29384d962ec8f487f824214744498bba505a6db0c59Randy Pan
29484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final PeriodicScanListener mPeriodicScanListener = new PeriodicScanListener();
29584d962ec8f487f824214744498bba505a6db0c59Randy Pan
29684d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Single scan results listener. A single scan is initiated when
29784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Disconnected/ConnectedPNO scan found a valid network and woke up
29884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // the system, or by the watchdog timer.
29984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private class SingleScanListener implements WifiScanner.ScanListener {
30084d962ec8f487f824214744498bba505a6db0c59Randy Pan        private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
301bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        private final boolean mIsWatchdogTriggered;
302ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        private final boolean mIsFullBandScan;
303bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius
304304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan        SingleScanListener(boolean isWatchdogTriggered, boolean isFullBandScan) {
305bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius            mIsWatchdogTriggered = isWatchdogTriggered;
306ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            mIsFullBandScan = isFullBandScan;
307bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        }
30884d962ec8f487f824214744498bba505a6db0c59Randy Pan
30984d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void clearScanDetails() {
31084d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.clear();
31184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
31284d962ec8f487f824214744498bba505a6db0c59Randy Pan
31384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
31484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onSuccess() {
31584d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("SingleScanListener onSuccess");
31684d962ec8f487f824214744498bba505a6db0c59Randy Pan
31784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reset the count
31884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mSingleScanRestartCount = 0;
31984d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
32084d962ec8f487f824214744498bba505a6db0c59Randy Pan
32184d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
32284d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFailure(int reason, String description) {
32384d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "SingleScanListener onFailure:"
32484d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " reason: " + reason
32584d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " description: " + description);
32684d962ec8f487f824214744498bba505a6db0c59Randy Pan
32784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reschedule the scan
32884d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mSingleScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
329304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan                scheduleDelayedSingleScan(mIsWatchdogTriggered, mIsFullBandScan);
33084d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
33184d962ec8f487f824214744498bba505a6db0c59Randy Pan                mSingleScanRestartCount = 0;
33284d962ec8f487f824214744498bba505a6db0c59Randy Pan                Log.e(TAG, "Failed to successfully start single scan for "
33384d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + MAX_SCAN_RESTART_ALLOWED + " times");
33484d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
33584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
33684d962ec8f487f824214744498bba505a6db0c59Randy Pan
33784d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
33884d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPeriodChanged(int periodInMs) {
33984d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("SingleScanListener onPeriodChanged: "
34084d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + "actual scan period " + periodInMs + "ms");
34184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
34284d962ec8f487f824214744498bba505a6db0c59Randy Pan
34384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
34484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onResults(WifiScanner.ScanData[] results) {
345bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius            boolean wasConnectAttempted = handleScanResults(mScanDetails, "SingleScanListener");
346224198c8ba46f362a5df6d25f1b60e56f442b58bRoshan Pius            clearScanDetails();
347bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius            // update metrics if this was a watchdog triggered single scan
348bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius            if (mIsWatchdogTriggered) {
349bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                if (wasConnectAttempted) {
350bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                    if (mScreenOn) {
351bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                        mWifiMetrics.incrementNumConnectivityWatchdogBackgroundBad();
352bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                    } else {
353bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                        mWifiMetrics.incrementNumConnectivityWatchdogPnoBad();
354bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                    }
355bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                } else {
356bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                    if (mScreenOn) {
357bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                        mWifiMetrics.incrementNumConnectivityWatchdogBackgroundGood();
358bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                    } else {
359bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                        mWifiMetrics.incrementNumConnectivityWatchdogPnoGood();
360bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                    }
361bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                }
362bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius            }
36384d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
36484d962ec8f487f824214744498bba505a6db0c59Randy Pan
36584d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
36684d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFullResult(ScanResult fullScanResult) {
36784d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mDbg) {
36884d962ec8f487f824214744498bba505a6db0c59Randy Pan                localLog("SingleScanListener onFullResult: "
36984d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.SSID + " capabilities "
37084d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + fullScanResult.capabilities);
37184d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
37284d962ec8f487f824214744498bba505a6db0c59Randy Pan
37384d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult));
37484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
37584d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
37684d962ec8f487f824214744498bba505a6db0c59Randy Pan
37784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // re-enable this when b/27695292 is fixed
37884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // private final SingleScanListener mSingleScanListener = new SingleScanListener();
37984d962ec8f487f824214744498bba505a6db0c59Randy Pan
38084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // PNO scan results listener for both disconected and connected PNO scanning.
38184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // A PNO scan is initiated when screen is off.
38284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private class PnoScanListener implements WifiScanner.PnoScanListener {
38384d962ec8f487f824214744498bba505a6db0c59Randy Pan        private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
3843d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        private int mLowRssiNetworkRetryDelay =
3853d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                LOW_RSSI_NETWORK_RETRY_START_DELAY_MS;
38684d962ec8f487f824214744498bba505a6db0c59Randy Pan
38784d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void clearScanDetails() {
38884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanDetails.clear();
38984d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
39084d962ec8f487f824214744498bba505a6db0c59Randy Pan
3913d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // Reset to the start value when either a non-PNO scan is started or
3923d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // QNS selects a candidate from the PNO scan results.
3933d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        public void resetLowRssiNetworkRetryDelay() {
3943d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_START_DELAY_MS;
3953d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        }
3963d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
3973d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        @VisibleForTesting
3983d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        public int getLowRssiNetworkRetryDelay() {
3993d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            return mLowRssiNetworkRetryDelay;
4003d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        }
4013d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
40284d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
40384d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onSuccess() {
40484d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PnoScanListener onSuccess");
40584d962ec8f487f824214744498bba505a6db0c59Randy Pan
40684d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reset the count
40784d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanRestartCount = 0;
40884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
40984d962ec8f487f824214744498bba505a6db0c59Randy Pan
41084d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
41184d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFailure(int reason, String description) {
41284d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "PnoScanListener onFailure:"
41384d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " reason: " + reason
41484d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + " description: " + description);
41584d962ec8f487f824214744498bba505a6db0c59Randy Pan
41684d962ec8f487f824214744498bba505a6db0c59Randy Pan            // reschedule the scan
41784d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
4183d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                scheduleDelayedConnectivityScan(RESTART_SCAN_DELAY_MS);
41984d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
42084d962ec8f487f824214744498bba505a6db0c59Randy Pan                mScanRestartCount = 0;
42184d962ec8f487f824214744498bba505a6db0c59Randy Pan                Log.e(TAG, "Failed to successfully start PNO scan for "
42284d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + MAX_SCAN_RESTART_ALLOWED + " times");
42384d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
42484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
42584d962ec8f487f824214744498bba505a6db0c59Randy Pan
42684d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
42784d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPeriodChanged(int periodInMs) {
42884d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PnoScanListener onPeriodChanged: "
42984d962ec8f487f824214744498bba505a6db0c59Randy Pan                          + "actual scan period " + periodInMs + "ms");
43084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
43184d962ec8f487f824214744498bba505a6db0c59Randy Pan
43284d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Currently the PNO scan results doesn't include IE,
43384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // which contains information required by QNS. Ignore them
43484d962ec8f487f824214744498bba505a6db0c59Randy Pan        // for now.
43584d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
43684d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onResults(WifiScanner.ScanData[] results) {
43784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
43884d962ec8f487f824214744498bba505a6db0c59Randy Pan
43984d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
44084d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onFullResult(ScanResult fullScanResult) {
44184d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
44284d962ec8f487f824214744498bba505a6db0c59Randy Pan
44384d962ec8f487f824214744498bba505a6db0c59Randy Pan        @Override
44484d962ec8f487f824214744498bba505a6db0c59Randy Pan        public void onPnoNetworkFound(ScanResult[] results) {
44584d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("PnoScanListener: onPnoNetworkFound: results len = " + results.length);
44684d962ec8f487f824214744498bba505a6db0c59Randy Pan
44784d962ec8f487f824214744498bba505a6db0c59Randy Pan            for (ScanResult result: results) {
44884d962ec8f487f824214744498bba505a6db0c59Randy Pan                mScanDetails.add(ScanDetailUtil.toScanDetail(result));
44984d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
4503d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
4513d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            boolean wasConnectAttempted;
4523d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            wasConnectAttempted = handleScanResults(mScanDetails, "PnoScanListener");
453224198c8ba46f362a5df6d25f1b60e56f442b58bRoshan Pius            clearScanDetails();
4543d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
4553d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            if (!wasConnectAttempted) {
4563d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                // The scan results were rejected by QNS due to low RSSI values
4573d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                if (mLowRssiNetworkRetryDelay > LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS) {
4583d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                    mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS;
4593d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                }
4603d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                scheduleDelayedConnectivityScan(mLowRssiNetworkRetryDelay);
4613d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
4623d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                // Set up the delay value for next retry.
4633d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                mLowRssiNetworkRetryDelay *= 2;
4643d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            } else {
4653d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                resetLowRssiNetworkRetryDelay();
4663d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            }
46784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
46884d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
46984d962ec8f487f824214744498bba505a6db0c59Randy Pan
47084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private final PnoScanListener mPnoScanListener = new PnoScanListener();
47184d962ec8f487f824214744498bba505a6db0c59Randy Pan
47284d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
47384d962ec8f487f824214744498bba505a6db0c59Randy Pan     * WifiConnectivityManager constructor
47484d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
47584d962ec8f487f824214744498bba505a6db0c59Randy Pan    public WifiConnectivityManager(Context context, WifiStateMachine stateMachine,
47684d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,
47709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne                WifiQualifiedNetworkSelector qualifiedNetworkSelector,
478c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                WifiInjector wifiInjector, Looper looper) {
47984d962ec8f487f824214744498bba505a6db0c59Randy Pan        mStateMachine = stateMachine;
48084d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanner = scanner;
48184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mConfigManager = configManager;
48284d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiInfo = wifiInfo;
483fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mQualifiedNetworkSelector = qualifiedNetworkSelector;
48409abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog();
485bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        mWifiMetrics = wifiInjector.getWifiMetrics();
486fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
487c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan        mEventHandler = new Handler(looper);
488fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mClock = wifiInjector.getClock();
4894f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        mConnectionAttemptTimeStamps = new LinkedList<>();
49084d962ec8f487f824214744498bba505a6db0c59Randy Pan
49184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mMin5GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI;
49284d962ec8f487f824214744498bba505a6db0c59Randy Pan        mMin24GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI;
49384d962ec8f487f824214744498bba505a6db0c59Randy Pan        mBand5GHzBonus = WifiQualifiedNetworkSelector.BAND_AWARD_5GHz;
49473a52d3336a40903965b946f6d3624a223ad5aacSamuel Tan        mCurrentConnectionBonus = mConfigManager.mCurrentNetworkBoost.get();
49584d962ec8f487f824214744498bba505a6db0c59Randy Pan        mSameNetworkBonus = context.getResources().getInteger(
49684d962ec8f487f824214744498bba505a6db0c59Randy Pan                                R.integer.config_wifi_framework_SAME_BSSID_AWARD);
49784d962ec8f487f824214744498bba505a6db0c59Randy Pan        mSecureBonus = context.getResources().getInteger(
49884d962ec8f487f824214744498bba505a6db0c59Randy Pan                            R.integer.config_wifi_framework_SECURITY_AWARD);
49973a52d3336a40903965b946f6d3624a223ad5aacSamuel Tan        mInitialScoreMax = (mConfigManager.mThresholdSaturatedRssi24.get()
50084d962ec8f487f824214744498bba505a6db0c59Randy Pan                            + WifiQualifiedNetworkSelector.RSSI_SCORE_OFFSET)
50184d962ec8f487f824214744498bba505a6db0c59Randy Pan                            * WifiQualifiedNetworkSelector.RSSI_SCORE_SLOPE;
50284d962ec8f487f824214744498bba505a6db0c59Randy Pan
50384d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "PNO settings:" + " min5GHzRssi " + mMin5GHzRssi
50484d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " min24GHzRssi " + mMin24GHzRssi
50584d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " currentConnectionBonus " + mCurrentConnectionBonus
50684d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " sameNetworkBonus " + mSameNetworkBonus
50784d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " secureNetworkBonus " + mSecureBonus
50884d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " initialScoreMax " + mInitialScoreMax);
50984d962ec8f487f824214744498bba505a6db0c59Randy Pan
51084d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "ConnectivityScanManager initialized ");
51184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
51284d962ec8f487f824214744498bba505a6db0c59Randy Pan
51384d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
5144f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * This checks the connection attempt rate and recommends whether the connection attempt
5154f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * should be skipped or not. This attempts to rate limit the rate of connections to
5164f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * prevent us from flapping between networks and draining battery rapidly.
5174f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     */
518ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius    private boolean shouldSkipConnectionAttempt(Long timeMillis) {
5194f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        Iterator<Long> attemptIter = mConnectionAttemptTimeStamps.iterator();
5204f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        // First evict old entries from the queue.
521c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan        while (attemptIter.hasNext()) {
5224f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            Long connectionAttemptTimeMillis = attemptIter.next();
523ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            if ((timeMillis - connectionAttemptTimeMillis)
524c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                    > MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS) {
5254f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius                attemptIter.remove();
5264f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            } else {
5274f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius                // This list is sorted by timestamps, so we can skip any more checks
5284f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius                break;
5294f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            }
5304f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        }
5314f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        // If we've reached the max connection attempt rate, skip this connection attempt
5324f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        return (mConnectionAttemptTimeStamps.size() >= MAX_CONNECTION_ATTEMPTS_RATE);
5334f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    }
5344f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
5354f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    /**
5364f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * Add the current connection attempt timestamp to our queue of connection attempts.
5374f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     */
538ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius    private void noteConnectionAttempt(Long timeMillis) {
539ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        mConnectionAttemptTimeStamps.addLast(timeMillis);
5404f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    }
5414f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
5424f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    /**
5434f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * This is used to clear the connection attempt rate limiter. This is done when the user
5444f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     * explicitly tries to connect to a specified network.
5454f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius     */
5464f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    private void clearConnectionAttemptTimeStamps() {
5474f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        mConnectionAttemptTimeStamps.clear();
5484f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    }
5494f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
5504f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius    /**
55184d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Attempt to connect to a network candidate.
55284d962ec8f487f824214744498bba505a6db0c59Randy Pan     *
55384d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Based on the currently connected network, this menthod determines whether we should
55484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * connect or roam to the network candidate recommended by QNS.
55584d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
55684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void connectToNetwork(WifiConfiguration candidate) {
55784d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();
55884d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (scanResultCandidate == null) {
55984d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.e(TAG, "connectToNetwork: bad candidate - "  + candidate
56084d962ec8f487f824214744498bba505a6db0c59Randy Pan                    + " scanResult: " + scanResultCandidate);
56184d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
56284d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
56384d962ec8f487f824214744498bba505a6db0c59Randy Pan
56484d962ec8f487f824214744498bba505a6db0c59Randy Pan        String targetBssid = scanResultCandidate.BSSID;
56584d962ec8f487f824214744498bba505a6db0c59Randy Pan        String targetAssociationId = candidate.SSID + " : " + targetBssid;
56650abba06efa7834b5309df561375e4a2e2df630dRandy Pan
56750abba06efa7834b5309df561375e4a2e2df630dRandy Pan        // Check if we are already connected or in the process of connecting to the target
56850abba06efa7834b5309df561375e4a2e2df630dRandy Pan        // BSSID. mWifiInfo.mBSSID tracks the currently connected BSSID. This is checked just
56950abba06efa7834b5309df561375e4a2e2df630dRandy Pan        // in case the firmware automatically roamed to a BSSID different from what QNS
57050abba06efa7834b5309df561375e4a2e2df630dRandy Pan        // selected.
57150abba06efa7834b5309df561375e4a2e2df630dRandy Pan        if (targetBssid != null
57250abba06efa7834b5309df561375e4a2e2df630dRandy Pan                && (targetBssid.equals(mLastConnectionAttemptBssid)
57350abba06efa7834b5309df561375e4a2e2df630dRandy Pan                    || targetBssid.equals(mWifiInfo.getBSSID()))
57450abba06efa7834b5309df561375e4a2e2df630dRandy Pan                && SupplicantState.isConnecting(mWifiInfo.getSupplicantState())) {
575eeb1a3c3cb4c09f925496000392d63b2b28301f7Randy Pan            localLog("connectToNetwork: Either already connected "
576eeb1a3c3cb4c09f925496000392d63b2b28301f7Randy Pan                    + "or is connecting to " + targetAssociationId);
57784d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
57884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
57984d962ec8f487f824214744498bba505a6db0c59Randy Pan
580ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        Long elapsedTimeMillis = mClock.elapsedRealtime();
581ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        if (!mScreenOn && shouldSkipConnectionAttempt(elapsedTimeMillis)) {
5824f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            localLog("connectToNetwork: Too many connection attempts. Skipping this attempt!");
583d54ddacc42d9cd929d40b1df391895293bacafe2Roshan Pius            mTotalConnectivityAttemptsRateLimited++;
5844f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius            return;
5854f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        }
586ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        noteConnectionAttempt(elapsedTimeMillis);
5874f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius
58850abba06efa7834b5309df561375e4a2e2df630dRandy Pan        mLastConnectionAttemptBssid = targetBssid;
58950abba06efa7834b5309df561375e4a2e2df630dRandy Pan
59084d962ec8f487f824214744498bba505a6db0c59Randy Pan        WifiConfiguration currentConnectedNetwork = mConfigManager
59184d962ec8f487f824214744498bba505a6db0c59Randy Pan                .getWifiConfiguration(mWifiInfo.getNetworkId());
59284d962ec8f487f824214744498bba505a6db0c59Randy Pan        String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" :
59384d962ec8f487f824214744498bba505a6db0c59Randy Pan                (mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID());
59484d962ec8f487f824214744498bba505a6db0c59Randy Pan
59584d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (currentConnectedNetwork != null
59684d962ec8f487f824214744498bba505a6db0c59Randy Pan                && (currentConnectedNetwork.networkId == candidate.networkId
59784d962ec8f487f824214744498bba505a6db0c59Randy Pan                || currentConnectedNetwork.isLinked(candidate))) {
59884d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("connectToNetwork: Roaming from " + currentAssociationId + " to "
59984d962ec8f487f824214744498bba505a6db0c59Randy Pan                        + targetAssociationId);
60084d962ec8f487f824214744498bba505a6db0c59Randy Pan            mStateMachine.autoRoamToNetwork(candidate.networkId, scanResultCandidate);
60184d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
60284d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("connectToNetwork: Reconnect from " + currentAssociationId + " to "
60384d962ec8f487f824214744498bba505a6db0c59Randy Pan                        + targetAssociationId);
60484d962ec8f487f824214744498bba505a6db0c59Randy Pan            mStateMachine.autoConnectToNetwork(candidate.networkId, scanResultCandidate.BSSID);
60584d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
60684d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
60784d962ec8f487f824214744498bba505a6db0c59Randy Pan
60884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Helper for selecting the band for connectivity scan
60984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private int getScanBand() {
610ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        return getScanBand(true);
611ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    }
612ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
613ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    private int getScanBand(boolean isFullBandScan) {
614ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        if (isFullBandScan) {
615ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            int freqBand = mStateMachine.getFrequencyBand();
616ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_5GHZ) {
617ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan                return WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS;
618ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            } else if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_2GHZ) {
619ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan                return WifiScanner.WIFI_BAND_24_GHZ;
620ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            } else {
621ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan                return WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
622ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            }
623ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        } else {
624ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            // Use channel list instead.
625ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            return WifiScanner.WIFI_BAND_UNSPECIFIED;
626ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        }
627ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    }
628ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
629fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    // Helper for setting the channels for connectivity scan when band is unspecified. Returns
630fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    // false if we can't retrieve the info.
631fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    private boolean setScanChannels(ScanSettings settings) {
632ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        WifiConfiguration config = mStateMachine.getCurrentWifiConfiguration();
633ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
634ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        if (config == null) {
635fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            return false;
636ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        }
637ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
638304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan        HashSet<Integer> freqs = mConfigManager.makeChannelList(config, CHANNEL_LIST_AGE_MS);
639ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
640ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        if (freqs != null && freqs.size() != 0) {
641ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            int index = 0;
642ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            settings.channels = new WifiScanner.ChannelSpec[freqs.size()];
643ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            for (Integer freq : freqs) {
644ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan                settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
645ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            }
646fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            return true;
64784d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
648fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            localLog("No scan channels for " + config.configKey() + ". Perform full band scan");
649fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            return false;
65084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
65184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
65284d962ec8f487f824214744498bba505a6db0c59Randy Pan
65384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Watchdog timer handler
65484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void watchdogHandler() {
65584d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("watchdogHandler");
65684d962ec8f487f824214744498bba505a6db0c59Randy Pan
65784d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Schedule the next timer and start a single scan if we are in disconnected state.
65884d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Otherwise, the watchdog timer will be scheduled when entering disconnected
65984d962ec8f487f824214744498bba505a6db0c59Randy Pan        // state.
66084d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mWifiState == WIFI_STATE_DISCONNECTED) {
66184d962ec8f487f824214744498bba505a6db0c59Randy Pan            Log.i(TAG, "start a single scan from watchdogHandler");
66284d962ec8f487f824214744498bba505a6db0c59Randy Pan
66384d962ec8f487f824214744498bba505a6db0c59Randy Pan            scheduleWatchdogTimer();
664304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan            startSingleScan(true, true);
665ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        }
666ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    }
667ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
668ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    // Start a single scan and set up the interval for next single scan.
669ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    private void startPeriodicSingleScan() {
670c2963eb07660a06592c60224279685166390217dRandy Pan        long currentTimeStamp = mClock.elapsedRealtime();
671c2963eb07660a06592c60224279685166390217dRandy Pan
672016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        if (mLastPeriodicSingleScanTimeStamp != RESET_TIME_STAMP) {
673c2963eb07660a06592c60224279685166390217dRandy Pan            long msSinceLastScan = currentTimeStamp - mLastPeriodicSingleScanTimeStamp;
674c2963eb07660a06592c60224279685166390217dRandy Pan            if (msSinceLastScan < PERIODIC_SCAN_INTERVAL_MS) {
675c2963eb07660a06592c60224279685166390217dRandy Pan                localLog("Last periodic single scan started " + msSinceLastScan
676c2963eb07660a06592c60224279685166390217dRandy Pan                        + "ms ago, defer this new scan request.");
677c2963eb07660a06592c60224279685166390217dRandy Pan                schedulePeriodicScanTimer(PERIODIC_SCAN_INTERVAL_MS - (int) msSinceLastScan);
678c2963eb07660a06592c60224279685166390217dRandy Pan                return;
679c2963eb07660a06592c60224279685166390217dRandy Pan            }
680c2963eb07660a06592c60224279685166390217dRandy Pan        }
681c2963eb07660a06592c60224279685166390217dRandy Pan
682ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        boolean isFullBandScan = true;
683ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
684ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        // If the WiFi traffic is heavy, only partial scan is initiated.
685ee9329dc901d59b8ae1e39edac99bd9d91306d2fRandy Pan        if (mWifiState == WIFI_STATE_CONNECTED
686ee9329dc901d59b8ae1e39edac99bd9d91306d2fRandy Pan                && (mWifiInfo.txSuccessRate
687ee9329dc901d59b8ae1e39edac99bd9d91306d2fRandy Pan                            > mConfigManager.MAX_TX_PACKET_FOR_FULL_SCANS
688ee9329dc901d59b8ae1e39edac99bd9d91306d2fRandy Pan                    || mWifiInfo.rxSuccessRate
689ee9329dc901d59b8ae1e39edac99bd9d91306d2fRandy Pan                            > mConfigManager.MAX_RX_PACKET_FOR_FULL_SCANS)) {
69046604d0d8d27c9dbdf986032de6e906e331f80ceRandy Pan            localLog("No full band scan due to heavy traffic, txSuccessRate="
69146604d0d8d27c9dbdf986032de6e906e331f80ceRandy Pan                        + mWifiInfo.txSuccessRate + " rxSuccessRate="
69246604d0d8d27c9dbdf986032de6e906e331f80ceRandy Pan                        + mWifiInfo.rxSuccessRate);
693ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            isFullBandScan = false;
694ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        }
695ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
696c2963eb07660a06592c60224279685166390217dRandy Pan        mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
697304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan        startSingleScan(false, isFullBandScan);
698ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
699ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan
700ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        // Set up the next scan interval in an exponential backoff fashion.
701ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        mPeriodicSingleScanInterval *= 2;
702ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        if (mPeriodicSingleScanInterval >  MAX_PERIODIC_SCAN_INTERVAL_MS) {
703ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS;
70484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
70584d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
70684d962ec8f487f824214744498bba505a6db0c59Randy Pan
707016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    // Reset the last periodic single scan time stamp so that the next periodic single
708016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    // scan can start immediately.
709016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    private void resetLastPeriodicSingleScanTimeStamp() {
710016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP;
711016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    }
712016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
71384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Periodic scan timer handler
71484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void periodicScanTimerHandler() {
71584d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("periodicScanTimerHandler");
71684d962ec8f487f824214744498bba505a6db0c59Randy Pan
71784d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Schedule the next timer and start a single scan if screen is on.
71884d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mScreenOn) {
719ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            startPeriodicSingleScan();
72084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
72184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
72284d962ec8f487f824214744498bba505a6db0c59Randy Pan
7233d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // Start a single scan
724304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan    private void startSingleScan(boolean isWatchdogTriggered, boolean isFullBandScan) {
725466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
72684d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
72784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
72884d962ec8f487f824214744498bba505a6db0c59Randy Pan
7293d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        mPnoScanListener.resetLowRssiNetworkRetryDelay();
7303d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
73184d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanSettings settings = new ScanSettings();
732ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        if (!isFullBandScan) {
733fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            if (!setScanChannels(settings)) {
734fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                isFullBandScan = true;
735fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            }
736ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        }
737fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        settings.band = getScanBand(isFullBandScan);
73884d962ec8f487f824214744498bba505a6db0c59Randy Pan        settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
73984d962ec8f487f824214744498bba505a6db0c59Randy Pan                            | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
74084d962ec8f487f824214744498bba505a6db0c59Randy Pan        settings.numBssidsPerScan = 0;
74184d962ec8f487f824214744498bba505a6db0c59Randy Pan
74284d962ec8f487f824214744498bba505a6db0c59Randy Pan        //Retrieve the list of hidden networkId's to scan for.
74384d962ec8f487f824214744498bba505a6db0c59Randy Pan        Set<Integer> hiddenNetworkIds = mConfigManager.getHiddenConfiguredNetworkIds();
74484d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (hiddenNetworkIds != null && hiddenNetworkIds.size() > 0) {
74584d962ec8f487f824214744498bba505a6db0c59Randy Pan            int i = 0;
74684d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.hiddenNetworkIds = new int[hiddenNetworkIds.size()];
74784d962ec8f487f824214744498bba505a6db0c59Randy Pan            for (Integer netId : hiddenNetworkIds) {
74884d962ec8f487f824214744498bba505a6db0c59Randy Pan                settings.hiddenNetworkIds[i++] = netId;
74984d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
75084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
75184d962ec8f487f824214744498bba505a6db0c59Randy Pan
75284d962ec8f487f824214744498bba505a6db0c59Randy Pan        // re-enable this when b/27695292 is fixed
75384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // mSingleScanListener.clearScanDetails();
75448444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Wills        // mScanner.startScan(settings, mSingleScanListener, WIFI_WORK_SOURCE);
755ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        SingleScanListener singleScanListener =
756304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan                new SingleScanListener(isWatchdogTriggered, isFullBandScan);
75748444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Wills        mScanner.startScan(settings, singleScanListener, WIFI_WORK_SOURCE);
75884d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
75984d962ec8f487f824214744498bba505a6db0c59Randy Pan
76084d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a periodic scan when screen is on
761016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    private void startPeriodicScan(boolean scanImmediately) {
7623d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        mPnoScanListener.resetLowRssiNetworkRetryDelay();
7633d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
764ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        // Due to b/28020168, timer based single scan will be scheduled
765ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        // to provide periodic scan in an exponential backoff fashion.
76679e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        if (!ENABLE_BACKGROUND_SCAN) {
767016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan            if (scanImmediately) {
768016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan                resetLastPeriodicSingleScanTimeStamp();
769016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan            }
770ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
771ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan            startPeriodicSingleScan();
77284d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
77384d962ec8f487f824214744498bba505a6db0c59Randy Pan            ScanSettings settings = new ScanSettings();
77484d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.band = getScanBand();
77584d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
77684d962ec8f487f824214744498bba505a6db0c59Randy Pan                                | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
77784d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.numBssidsPerScan = 0;
77884d962ec8f487f824214744498bba505a6db0c59Randy Pan            settings.periodInMs = PERIODIC_SCAN_INTERVAL_MS;
77984d962ec8f487f824214744498bba505a6db0c59Randy Pan
78084d962ec8f487f824214744498bba505a6db0c59Randy Pan            mPeriodicScanListener.clearScanDetails();
78148444cb4214a48a3a0bf4bbb93945c2aa68c9980Mitchell Wills            mScanner.startBackgroundScan(settings, mPeriodicScanListener, WIFI_WORK_SOURCE);
78284d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
78384d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
78484d962ec8f487f824214744498bba505a6db0c59Randy Pan
78584d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a DisconnectedPNO scan when screen is off and Wifi is disconnected
78684d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void startDisconnectedPnoScan() {
78784d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize PNO settings
78884d962ec8f487f824214744498bba505a6db0c59Randy Pan        PnoSettings pnoSettings = new PnoSettings();
78984d962ec8f487f824214744498bba505a6db0c59Randy Pan        ArrayList<PnoSettings.PnoNetwork> pnoNetworkList =
790329b3a9a9bc32d14649e91c15876ea7f95f148d1Roshan Pius                mConfigManager.retrieveDisconnectedPnoNetworkList();
79184d962ec8f487f824214744498bba505a6db0c59Randy Pan        int listSize = pnoNetworkList.size();
79284d962ec8f487f824214744498bba505a6db0c59Randy Pan
79384d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (listSize == 0) {
79484d962ec8f487f824214744498bba505a6db0c59Randy Pan            // No saved network
79584d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("No saved network for starting disconnected PNO.");
79684d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
79784d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
79884d962ec8f487f824214744498bba505a6db0c59Randy Pan
79984d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize];
80084d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList);
80184d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min5GHzRssi = mMin5GHzRssi;
80284d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min24GHzRssi = mMin24GHzRssi;
80384d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.initialScoreMax = mInitialScoreMax;
80484d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.currentConnectionBonus = mCurrentConnectionBonus;
80584d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.sameNetworkBonus = mSameNetworkBonus;
80684d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.secureBonus = mSecureBonus;
80784d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.band5GHzBonus = mBand5GHzBonus;
80884d962ec8f487f824214744498bba505a6db0c59Randy Pan
80984d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize scan settings
81084d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanSettings scanSettings = new ScanSettings();
81184d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.band = getScanBand();
81284d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH;
81384d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.numBssidsPerScan = 0;
81479e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        scanSettings.periodInMs = DISCONNECTED_PNO_SCAN_INTERVAL_MS;
81584d962ec8f487f824214744498bba505a6db0c59Randy Pan        // TODO: enable exponential back off scan later to further save energy
81684d962ec8f487f824214744498bba505a6db0c59Randy Pan        // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs;
81784d962ec8f487f824214744498bba505a6db0c59Randy Pan
81884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mPnoScanListener.clearScanDetails();
81984d962ec8f487f824214744498bba505a6db0c59Randy Pan
82084d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener);
82184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
82284d962ec8f487f824214744498bba505a6db0c59Randy Pan
82384d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a ConnectedPNO scan when screen is off and Wifi is connected
82484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void startConnectedPnoScan() {
82584d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Disable ConnectedPNO for now due to b/28020168
82679e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        if (!ENABLE_CONNECTED_PNO_SCAN) {
82784d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
82884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
82984d962ec8f487f824214744498bba505a6db0c59Randy Pan
83084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize PNO settings
83184d962ec8f487f824214744498bba505a6db0c59Randy Pan        PnoSettings pnoSettings = new PnoSettings();
83284d962ec8f487f824214744498bba505a6db0c59Randy Pan        ArrayList<PnoSettings.PnoNetwork> pnoNetworkList =
83384d962ec8f487f824214744498bba505a6db0c59Randy Pan                mConfigManager.retrieveConnectedPnoNetworkList();
83484d962ec8f487f824214744498bba505a6db0c59Randy Pan        int listSize = pnoNetworkList.size();
83584d962ec8f487f824214744498bba505a6db0c59Randy Pan
83684d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (listSize == 0) {
83784d962ec8f487f824214744498bba505a6db0c59Randy Pan            // No saved network
83884d962ec8f487f824214744498bba505a6db0c59Randy Pan            localLog("No saved network for starting connected PNO.");
83984d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
84084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
84184d962ec8f487f824214744498bba505a6db0c59Randy Pan
84284d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize];
84384d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList);
84484d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min5GHzRssi = mMin5GHzRssi;
84584d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.min24GHzRssi = mMin24GHzRssi;
84684d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.initialScoreMax = mInitialScoreMax;
84784d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.currentConnectionBonus = mCurrentConnectionBonus;
84884d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.sameNetworkBonus = mSameNetworkBonus;
84984d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.secureBonus = mSecureBonus;
85084d962ec8f487f824214744498bba505a6db0c59Randy Pan        pnoSettings.band5GHzBonus = mBand5GHzBonus;
85184d962ec8f487f824214744498bba505a6db0c59Randy Pan
85284d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Initialize scan settings
85384d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanSettings scanSettings = new ScanSettings();
85484d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.band = getScanBand();
85584d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH;
85684d962ec8f487f824214744498bba505a6db0c59Randy Pan        scanSettings.numBssidsPerScan = 0;
85779e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        scanSettings.periodInMs = CONNECTED_PNO_SCAN_INTERVAL_MS;
85884d962ec8f487f824214744498bba505a6db0c59Randy Pan        // TODO: enable exponential back off scan later to further save energy
85984d962ec8f487f824214744498bba505a6db0c59Randy Pan        // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs;
86084d962ec8f487f824214744498bba505a6db0c59Randy Pan
86184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mPnoScanListener.clearScanDetails();
86284d962ec8f487f824214744498bba505a6db0c59Randy Pan
86384d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanner.startConnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener);
86484d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
86584d962ec8f487f824214744498bba505a6db0c59Randy Pan
86684d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Set up watchdog timer
86784d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void scheduleWatchdogTimer() {
86884d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "scheduleWatchdogTimer");
86984d962ec8f487f824214744498bba505a6db0c59Randy Pan
870ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
871ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                            mClock.elapsedRealtime() + WATCHDOG_INTERVAL_MS,
8721d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                            WATCHDOG_TIMER_TAG,
873c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                            mWatchdogListener, mEventHandler);
87484d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
87584d962ec8f487f824214744498bba505a6db0c59Randy Pan
87684d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Set up periodic scan timer
877ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan    private void schedulePeriodicScanTimer(int intervalMs) {
878ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
879ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                            mClock.elapsedRealtime() + intervalMs,
8801d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                            PERIODIC_SCAN_TIMER_TAG,
881c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                            mPeriodicScanTimerListener, mEventHandler);
88284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
88384d962ec8f487f824214744498bba505a6db0c59Randy Pan
88484d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Set up timer to start a delayed single scan after RESTART_SCAN_DELAY_MS
885304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan    private void scheduleDelayedSingleScan(boolean isWatchdogTriggered, boolean isFullBandScan) {
88684d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("scheduleDelayedSingleScan");
88784d962ec8f487f824214744498bba505a6db0c59Randy Pan
888bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius        RestartSingleScanListener restartSingleScanListener =
889304d3451b9245f7c7bb5e81465561f0eb63b2473Randy Pan                new RestartSingleScanListener(isWatchdogTriggered, isFullBandScan);
890ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
891ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                            mClock.elapsedRealtime() + RESTART_SCAN_DELAY_MS,
8921d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                            RESTART_SINGLE_SCAN_TIMER_TAG,
893bacd0dca59fbba9f650a421a3d3b0dc5fa2eb606Roshan Pius                            restartSingleScanListener, mEventHandler);
89484d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
89584d962ec8f487f824214744498bba505a6db0c59Randy Pan
8963d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    // Set up timer to start a delayed scan after msFromNow milli-seconds
8973d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    private void scheduleDelayedConnectivityScan(int msFromNow) {
89884d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("scheduleDelayedConnectivityScan");
89984d962ec8f487f824214744498bba505a6db0c59Randy Pan
900ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
901ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius                            mClock.elapsedRealtime() + msFromNow,
9021d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                            RESTART_CONNECTIVITY_SCAN_TIMER_TAG,
903c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                            mRestartScanListener, mEventHandler);
90484d962ec8f487f824214744498bba505a6db0c59Randy Pan
90584d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
90684d962ec8f487f824214744498bba505a6db0c59Randy Pan
90784d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Start a connectivity scan. The scan method is chosen according to
90884d962ec8f487f824214744498bba505a6db0c59Randy Pan    // the current screen state and WiFi state.
909016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    private void startConnectivityScan(boolean scanImmediately) {
91084d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("startConnectivityScan: screenOn=" + mScreenOn
91184d962ec8f487f824214744498bba505a6db0c59Randy Pan                        + " wifiState=" + mWifiState
912016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan                        + " scanImmediately=" + scanImmediately
913466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan                        + " wifiEnabled=" + mWifiEnabled
914466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan                        + " wifiConnectivityManagerEnabled="
915466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan                        + mWifiConnectivityManagerEnabled);
91684d962ec8f487f824214744498bba505a6db0c59Randy Pan
917466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
91884d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
91984d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
92084d962ec8f487f824214744498bba505a6db0c59Randy Pan
92184d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Always stop outstanding connecivity scan if there is any
92284d962ec8f487f824214744498bba505a6db0c59Randy Pan        stopConnectivityScan();
92384d962ec8f487f824214744498bba505a6db0c59Randy Pan
92484d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Don't start a connectivity scan while Wifi is in the transition
92584d962ec8f487f824214744498bba505a6db0c59Randy Pan        // between connected and disconnected states.
92684d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mWifiState != WIFI_STATE_CONNECTED && mWifiState != WIFI_STATE_DISCONNECTED) {
92784d962ec8f487f824214744498bba505a6db0c59Randy Pan            return;
92884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
92984d962ec8f487f824214744498bba505a6db0c59Randy Pan
93084d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mScreenOn) {
931016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan            startPeriodicScan(scanImmediately);
93284d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else { // screenOff
93384d962ec8f487f824214744498bba505a6db0c59Randy Pan            if (mWifiState == WIFI_STATE_CONNECTED) {
93484d962ec8f487f824214744498bba505a6db0c59Randy Pan                startConnectedPnoScan();
93584d962ec8f487f824214744498bba505a6db0c59Randy Pan            } else {
93684d962ec8f487f824214744498bba505a6db0c59Randy Pan                startDisconnectedPnoScan();
93784d962ec8f487f824214744498bba505a6db0c59Randy Pan            }
93884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
93984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
94084d962ec8f487f824214744498bba505a6db0c59Randy Pan
94184d962ec8f487f824214744498bba505a6db0c59Randy Pan    // Stop connectivity scan if there is any.
94284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private void stopConnectivityScan() {
943ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        // Due to b/28020168, timer based single scan will be scheduled
944ae9e0ef3efdd579fab8d89b5c653f4069e7ac883Randy Pan        // to provide periodic scan in an exponential backoff fashion.
94579e3bf8db6b566a5b3c7065cdd43f87f07e73747Roshan Pius        if (!ENABLE_BACKGROUND_SCAN) {
94684d962ec8f487f824214744498bba505a6db0c59Randy Pan            mAlarmManager.cancel(mPeriodicScanTimerListener);
94784d962ec8f487f824214744498bba505a6db0c59Randy Pan        } else {
94884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mScanner.stopBackgroundScan(mPeriodicScanListener);
94984d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
950f37079e3d8f4aca3242a971cbaef732fe1b75bdeRoshan Pius        mScanner.stopPnoScan(mPnoScanListener);
95184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScanRestartCount = 0;
95284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
95384d962ec8f487f824214744498bba505a6db0c59Randy Pan
95484d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
95584d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler for screen state (on/off) changes
95684d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
95784d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void handleScreenStateChanged(boolean screenOn) {
95884d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("handleScreenStateChanged: screenOn=" + screenOn);
95984d962ec8f487f824214744498bba505a6db0c59Randy Pan
96084d962ec8f487f824214744498bba505a6db0c59Randy Pan        mScreenOn = screenOn;
96184d962ec8f487f824214744498bba505a6db0c59Randy Pan
962016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        startConnectivityScan(SCAN_ON_SCHEDULE);
96384d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
96484d962ec8f487f824214744498bba505a6db0c59Randy Pan
96584d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
96684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler for WiFi state (connected/disconnected) changes
96784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
96884d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void handleConnectionStateChanged(int state) {
96984d962ec8f487f824214744498bba505a6db0c59Randy Pan        localLog("handleConnectionStateChanged: state=" + state);
97084d962ec8f487f824214744498bba505a6db0c59Randy Pan
97184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiState = state;
97284d962ec8f487f824214744498bba505a6db0c59Randy Pan
97384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Kick off the watchdog timer if entering disconnected state
97484d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mWifiState == WIFI_STATE_DISCONNECTED) {
97584d962ec8f487f824214744498bba505a6db0c59Randy Pan            scheduleWatchdogTimer();
97684d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
97784d962ec8f487f824214744498bba505a6db0c59Randy Pan
978016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        startConnectivityScan(SCAN_ON_SCHEDULE);
97984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
98084d962ec8f487f824214744498bba505a6db0c59Randy Pan
98184d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
98284d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler when user toggles whether untrusted connection is allowed
98384d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
98484d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void setUntrustedConnectionAllowed(boolean allowed) {
98584d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "setUntrustedConnectionAllowed: allowed=" + allowed);
98684d962ec8f487f824214744498bba505a6db0c59Randy Pan
98784d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (mUntrustedConnectionAllowed != allowed) {
98884d962ec8f487f824214744498bba505a6db0c59Randy Pan            mUntrustedConnectionAllowed = allowed;
989016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan            startConnectivityScan(SCAN_IMMEDIATELY);
99084d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
99184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
99284d962ec8f487f824214744498bba505a6db0c59Randy Pan
99384d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
99484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler when user specifies a particular network to connect to
99584d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
99684d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void connectToUserSelectNetwork(int netId, boolean persistent) {
99784d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "connectToUserSelectNetwork: netId=" + netId
99884d962ec8f487f824214744498bba505a6db0c59Randy Pan                   + " persist=" + persistent);
99984d962ec8f487f824214744498bba505a6db0c59Randy Pan
100084d962ec8f487f824214744498bba505a6db0c59Randy Pan        mQualifiedNetworkSelector.userSelectNetwork(netId, persistent);
100184d962ec8f487f824214744498bba505a6db0c59Randy Pan
10024f5054647a2f4cac54a78d6e3bf3efa0727b488aRoshan Pius        clearConnectionAttemptTimeStamps();
100384d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
100484d962ec8f487f824214744498bba505a6db0c59Randy Pan
100584d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
100684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Handler for on-demand connectivity scan
100784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
100884d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void forceConnectivityScan() {
100984d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "forceConnectivityScan");
101084d962ec8f487f824214744498bba505a6db0c59Randy Pan
1011016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        startConnectivityScan(SCAN_IMMEDIATELY);
101284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
101384d962ec8f487f824214744498bba505a6db0c59Randy Pan
101484d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
101584d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Track whether a BSSID should be enabled or disabled for QNS
101684d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
101784d962ec8f487f824214744498bba505a6db0c59Randy Pan    public boolean trackBssid(String bssid, boolean enable) {
101884d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "trackBssid: " + (enable ? "enable " : "disable ") + bssid);
101984d962ec8f487f824214744498bba505a6db0c59Randy Pan
102084d962ec8f487f824214744498bba505a6db0c59Randy Pan        boolean ret = mQualifiedNetworkSelector
102184d962ec8f487f824214744498bba505a6db0c59Randy Pan                            .enableBssidForQualityNetworkSelection(bssid, enable);
102284d962ec8f487f824214744498bba505a6db0c59Randy Pan
102384d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (ret && !enable) {
102484d962ec8f487f824214744498bba505a6db0c59Randy Pan            // Disabling a BSSID can happen when the AP candidate to connect to has
102584d962ec8f487f824214744498bba505a6db0c59Randy Pan            // no capacity for new stations. We start another scan immediately so that QNS
102684d962ec8f487f824214744498bba505a6db0c59Randy Pan            // can give us another candidate to connect to.
1027016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan            startConnectivityScan(SCAN_IMMEDIATELY);
102884d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
102984d962ec8f487f824214744498bba505a6db0c59Randy Pan
103084d962ec8f487f824214744498bba505a6db0c59Randy Pan        return ret;
103184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
103284d962ec8f487f824214744498bba505a6db0c59Randy Pan
103384d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
103484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Set band preference when doing scan and making connection
103584d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
103684d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void setUserPreferredBand(int band) {
103784d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "User band preference: " + band);
103884d962ec8f487f824214744498bba505a6db0c59Randy Pan
103984d962ec8f487f824214744498bba505a6db0c59Randy Pan        mQualifiedNetworkSelector.setUserPreferredBand(band);
1040016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        startConnectivityScan(SCAN_IMMEDIATELY);
104184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
104284d962ec8f487f824214744498bba505a6db0c59Randy Pan
104384d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
104484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Inform WiFi is enabled for connection or not
104584d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
104684d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void setWifiEnabled(boolean enable) {
104784d962ec8f487f824214744498bba505a6db0c59Randy Pan        Log.i(TAG, "Set WiFi " + (enable ? "enabled" : "disabled"));
104884d962ec8f487f824214744498bba505a6db0c59Randy Pan
104984d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiEnabled = enable;
105084d962ec8f487f824214744498bba505a6db0c59Randy Pan
105184d962ec8f487f824214744498bba505a6db0c59Randy Pan        if (!mWifiEnabled) {
105284d962ec8f487f824214744498bba505a6db0c59Randy Pan            stopConnectivityScan();
1053016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan            resetLastPeriodicSingleScanTimeStamp();
105484d962ec8f487f824214744498bba505a6db0c59Randy Pan        }
105584d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
105684d962ec8f487f824214744498bba505a6db0c59Randy Pan
105784d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
1058466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan     * Turn on/off the WifiConnectivityMangager at runtime
1059466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan     */
1060466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    public void enable(boolean enable) {
1061466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        Log.i(TAG, "Set WiFiConnectivityManager " + (enable ? "enabled" : "disabled"));
1062466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan
1063466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        mWifiConnectivityManagerEnabled = enable;
1064466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan
1065466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        if (!mWifiConnectivityManagerEnabled) {
1066466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan            stopConnectivityScan();
1067016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan            resetLastPeriodicSingleScanTimeStamp();
1068466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan        }
1069466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    }
1070466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan
1071466158a6669d51541ce6c5c4e04a71dad36cdb4eRandy Pan    /**
107284d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Enable/disable verbose logging
107384d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
107484d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void enableVerboseLogging(int verbose) {
107584d962ec8f487f824214744498bba505a6db0c59Randy Pan        mDbg = verbose > 0;
107684d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
107784d962ec8f487f824214744498bba505a6db0c59Randy Pan
107884d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
107984d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Dump the local log buffer
108084d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
108184d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
108284d962ec8f487f824214744498bba505a6db0c59Randy Pan        pw.println("Dump of WifiConnectivityManager");
108384d962ec8f487f824214744498bba505a6db0c59Randy Pan        pw.println("WifiConnectivityManager - Log Begin ----");
108450abba06efa7834b5309df561375e4a2e2df630dRandy Pan        pw.println("WifiConnectivityManager - Number of connectivity attempts rate limited: "
108550abba06efa7834b5309df561375e4a2e2df630dRandy Pan                + mTotalConnectivityAttemptsRateLimited);
108684d962ec8f487f824214744498bba505a6db0c59Randy Pan        mLocalLog.dump(fd, pw, args);
108784d962ec8f487f824214744498bba505a6db0c59Randy Pan        pw.println("WifiConnectivityManager - Log End ----");
108884d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
10893d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
10903d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    @VisibleForTesting
10913d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    int getLowRssiNetworkRetryDelay() {
10923d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        return mPnoScanListener.getLowRssiNetworkRetryDelay();
10933d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    }
1094016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
1095016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    @VisibleForTesting
1096016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    long getLastPeriodicSingleScanTimeStamp() {
1097016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        return mLastPeriodicSingleScanTimeStamp;
1098016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    }
109984d962ec8f487f824214744498bba505a6db0c59Randy Pan}
1100