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
1984d962ec8f487f824214744498bba505a6db0c59Randy Panimport static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig;
20cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Panimport static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE;
2184d962ec8f487f824214744498bba505a6db0c59Randy Pan
22fb196453c07daad5e525520cecad84cec5d89fb7Roshan Piusimport static org.junit.Assert.*;
2384d962ec8f487f824214744498bba505a6db0c59Randy Panimport static org.mockito.Mockito.*;
2484d962ec8f487f824214744498bba505a6db0c59Randy Pan
2584d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.content.Context;
2684d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.content.res.Resources;
2784d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.ScanResult;
28fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Piusimport android.net.wifi.ScanResult.InformationElement;
2950abba06efa7834b5309df561375e4a2e2df630dRandy Panimport android.net.wifi.SupplicantState;
3084d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiConfiguration;
3184d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiInfo;
32fb196453c07daad5e525520cecad84cec5d89fb7Roshan Piusimport android.net.wifi.WifiManager;
3384d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiScanner;
34fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Piusimport android.net.wifi.WifiScanner.PnoScanListener;
35fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Piusimport android.net.wifi.WifiScanner.PnoSettings;
368cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Panimport android.net.wifi.WifiScanner.ScanData;
3784d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiScanner.ScanListener;
3884d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.net.wifi.WifiScanner.ScanSettings;
391d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Piusimport android.net.wifi.WifiSsid;
40ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Piusimport android.os.SystemClock;
41e78a18cf874b4d9bb5db2ef7804b8ac576e56489Mitchell Willsimport android.os.WorkSource;
4284d962ec8f487f824214744498bba505a6db0c59Randy Panimport android.test.suitebuilder.annotation.SmallTest;
4384d962ec8f487f824214744498bba505a6db0c59Randy Pan
4484d962ec8f487f824214744498bba505a6db0c59Randy Panimport com.android.internal.R;
4584d962ec8f487f824214744498bba505a6db0c59Randy Panimport com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
4684d962ec8f487f824214744498bba505a6db0c59Randy Pan
4784d962ec8f487f824214744498bba505a6db0c59Randy Panimport org.junit.After;
4884d962ec8f487f824214744498bba505a6db0c59Randy Panimport org.junit.Before;
4984d962ec8f487f824214744498bba505a6db0c59Randy Panimport org.junit.Test;
50cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Panimport org.mockito.ArgumentCaptor;
5184d962ec8f487f824214744498bba505a6db0c59Randy Pan
52fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Piusimport java.nio.charset.StandardCharsets;
53fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Piusimport java.util.ArrayList;
54fb196453c07daad5e525520cecad84cec5d89fb7Roshan Piusimport java.util.HashSet;
5584d962ec8f487f824214744498bba505a6db0c59Randy Panimport java.util.concurrent.atomic.AtomicInteger;
5684d962ec8f487f824214744498bba505a6db0c59Randy Pan
5784d962ec8f487f824214744498bba505a6db0c59Randy Pan/**
5884d962ec8f487f824214744498bba505a6db0c59Randy Pan * Unit tests for {@link com.android.server.wifi.WifiConnectivityManager}.
5984d962ec8f487f824214744498bba505a6db0c59Randy Pan */
6084d962ec8f487f824214744498bba505a6db0c59Randy Pan@SmallTest
6184d962ec8f487f824214744498bba505a6db0c59Randy Panpublic class WifiConnectivityManagerTest {
6284d962ec8f487f824214744498bba505a6db0c59Randy Pan
6384d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
6484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Called before each test
6584d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
6684d962ec8f487f824214744498bba505a6db0c59Randy Pan    @Before
6784d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void setUp() throws Exception {
6809abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiInjector = mockWifiInjector();
6909abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mResource = mockResource();
701d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mAlarmManager = new MockAlarmManager();
7109abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mContext = mockContext();
7209abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiStateMachine = mockWifiStateMachine();
7309abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiConfigManager = mockWifiConfigManager();
74fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiInfo = getWifiInfo();
758cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        mScanData = mockScanData();
7609abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiScanner = mockWifiScanner();
7709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiQNS = mockWifiQualifiedNetworkSelector();
7884d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager = new WifiConnectivityManager(mContext, mWifiStateMachine,
79c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan                mWifiScanner, mWifiConfigManager, mWifiInfo, mWifiQNS, mWifiInjector,
80c4d044acc589188f25b8dcd962db52e1fc08fe8dRandy Pan                mLooper.getLooper(), true);
8184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.setWifiEnabled(true);
82ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        when(mClock.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime());
8384d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
8484d962ec8f487f824214744498bba505a6db0c59Randy Pan
8584d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
8684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Called after each test
8784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
8884d962ec8f487f824214744498bba505a6db0c59Randy Pan    @After
8984d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void cleanup() {
9084d962ec8f487f824214744498bba505a6db0c59Randy Pan        validateMockitoUsage();
9184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
9284d962ec8f487f824214744498bba505a6db0c59Randy Pan
9384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private Resources mResource;
9484d962ec8f487f824214744498bba505a6db0c59Randy Pan    private Context mContext;
951d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    private MockAlarmManager mAlarmManager;
96c8a21e495dfaa5c44e87fda330621a1ed6c8aaceRandy Pan    private MockLooper mLooper = new MockLooper();
9784d962ec8f487f824214744498bba505a6db0c59Randy Pan    private WifiConnectivityManager mWifiConnectivityManager;
9884d962ec8f487f824214744498bba505a6db0c59Randy Pan    private WifiQualifiedNetworkSelector mWifiQNS;
9984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private WifiStateMachine mWifiStateMachine;
10084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private WifiScanner mWifiScanner;
1018cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan    private ScanData mScanData;
10284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private WifiConfigManager mWifiConfigManager;
10384d962ec8f487f824214744498bba505a6db0c59Randy Pan    private WifiInfo mWifiInfo;
104fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    private Clock mClock = mock(Clock.class);
10509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    private WifiLastResortWatchdog mWifiLastResortWatchdog;
1061d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    private WifiMetrics mWifiMetrics;
10709abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    private WifiInjector mWifiInjector;
10884d962ec8f487f824214744498bba505a6db0c59Randy Pan
10984d962ec8f487f824214744498bba505a6db0c59Randy Pan    private static final int CANDIDATE_NETWORK_ID = 0;
11084d962ec8f487f824214744498bba505a6db0c59Randy Pan    private static final String CANDIDATE_SSID = "\"AnSsid\"";
11184d962ec8f487f824214744498bba505a6db0c59Randy Pan    private static final String CANDIDATE_BSSID = "6c:f3:7f:ae:8c:f3";
11284d962ec8f487f824214744498bba505a6db0c59Randy Pan    private static final String TAG = "WifiConnectivityManager Unit Test";
113b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    private static final long CURRENT_SYSTEM_TIME_MS = 1000;
11484d962ec8f487f824214744498bba505a6db0c59Randy Pan
11509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    Resources mockResource() {
11684d962ec8f487f824214744498bba505a6db0c59Randy Pan        Resources resource = mock(Resources.class);
11784d962ec8f487f824214744498bba505a6db0c59Randy Pan
11884d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(resource.getInteger(R.integer.config_wifi_framework_SECURITY_AWARD)).thenReturn(80);
11984d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(resource.getInteger(R.integer.config_wifi_framework_SAME_BSSID_AWARD)).thenReturn(24);
12084d962ec8f487f824214744498bba505a6db0c59Randy Pan
12184d962ec8f487f824214744498bba505a6db0c59Randy Pan        return resource;
12284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
12384d962ec8f487f824214744498bba505a6db0c59Randy Pan
12409abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    Context mockContext() {
12584d962ec8f487f824214744498bba505a6db0c59Randy Pan        Context context = mock(Context.class);
12684d962ec8f487f824214744498bba505a6db0c59Randy Pan
12784d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(context.getResources()).thenReturn(mResource);
12884d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(
1291d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                mAlarmManager.getAlarmManager());
13084d962ec8f487f824214744498bba505a6db0c59Randy Pan
13184d962ec8f487f824214744498bba505a6db0c59Randy Pan        return context;
13284d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
13384d962ec8f487f824214744498bba505a6db0c59Randy Pan
1348cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan    ScanData mockScanData() {
1358cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        ScanData scanData = mock(ScanData.class);
1368cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
1378cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        when(scanData.isAllChannelsScanned()).thenReturn(true);
1388cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
1398cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        return scanData;
1408cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan    }
1418cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
14209abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    WifiScanner mockWifiScanner() {
14384d962ec8f487f824214744498bba505a6db0c59Randy Pan        WifiScanner scanner = mock(WifiScanner.class);
144cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        ArgumentCaptor<ScanListener> allSingleScanListenerCaptor =
145cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan                ArgumentCaptor.forClass(ScanListener.class);
146cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan
147cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        doNothing().when(scanner).registerScanListener(allSingleScanListenerCaptor.capture());
14884d962ec8f487f824214744498bba505a6db0c59Randy Pan
1498cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        ScanData[] scanDatas = new ScanData[1];
1508cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        scanDatas[0] = mScanData;
15184d962ec8f487f824214744498bba505a6db0c59Randy Pan
15284d962ec8f487f824214744498bba505a6db0c59Randy Pan        // do a synchronous answer for the ScanListener callbacks
15384d962ec8f487f824214744498bba505a6db0c59Randy Pan        doAnswer(new AnswerWithArguments() {
154e78a18cf874b4d9bb5db2ef7804b8ac576e56489Mitchell Wills                public void answer(ScanSettings settings, ScanListener listener,
155e78a18cf874b4d9bb5db2ef7804b8ac576e56489Mitchell Wills                        WorkSource workSource) throws Exception {
156fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    listener.onResults(scanDatas);
157e78a18cf874b4d9bb5db2ef7804b8ac576e56489Mitchell Wills                }}).when(scanner).startBackgroundScan(anyObject(), anyObject(), anyObject());
15884d962ec8f487f824214744498bba505a6db0c59Randy Pan
15984d962ec8f487f824214744498bba505a6db0c59Randy Pan        doAnswer(new AnswerWithArguments() {
160e78a18cf874b4d9bb5db2ef7804b8ac576e56489Mitchell Wills                public void answer(ScanSettings settings, ScanListener listener,
161e78a18cf874b4d9bb5db2ef7804b8ac576e56489Mitchell Wills                        WorkSource workSource) throws Exception {
162fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    listener.onResults(scanDatas);
163cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan                    allSingleScanListenerCaptor.getValue().onResults(scanDatas);
164e78a18cf874b4d9bb5db2ef7804b8ac576e56489Mitchell Wills                }}).when(scanner).startScan(anyObject(), anyObject(), anyObject());
16584d962ec8f487f824214744498bba505a6db0c59Randy Pan
166fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // This unfortunately needs to be a somewhat valid scan result, otherwise
167fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // |ScanDetailUtil.toScanDetail| raises exceptions.
168fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        final ScanResult[] scanResults = new ScanResult[1];
169fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        scanResults[0] = new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID),
170fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps",
171fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                -78, 2450, 1025, 22, 33, 20, 0, 0, true);
172fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        scanResults[0].informationElements = new InformationElement[1];
173fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        scanResults[0].informationElements[0] = new InformationElement();
174fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        scanResults[0].informationElements[0].id = InformationElement.EID_SSID;
175fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        scanResults[0].informationElements[0].bytes =
176fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                CANDIDATE_SSID.getBytes(StandardCharsets.UTF_8);
177fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
178fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        doAnswer(new AnswerWithArguments() {
179fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            public void answer(ScanSettings settings, PnoSettings pnoSettings,
180fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    PnoScanListener listener) throws Exception {
181fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                listener.onPnoNetworkFound(scanResults);
182fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            }}).when(scanner).startDisconnectedPnoScan(anyObject(), anyObject(), anyObject());
183fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
184fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        doAnswer(new AnswerWithArguments() {
185fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            public void answer(ScanSettings settings, PnoSettings pnoSettings,
186fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    PnoScanListener listener) throws Exception {
187fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                listener.onPnoNetworkFound(scanResults);
188fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            }}).when(scanner).startConnectedPnoScan(anyObject(), anyObject(), anyObject());
189fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
19084d962ec8f487f824214744498bba505a6db0c59Randy Pan        return scanner;
19184d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
19284d962ec8f487f824214744498bba505a6db0c59Randy Pan
19309abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    WifiStateMachine mockWifiStateMachine() {
19484d962ec8f487f824214744498bba505a6db0c59Randy Pan        WifiStateMachine stateMachine = mock(WifiStateMachine.class);
19584d962ec8f487f824214744498bba505a6db0c59Randy Pan
19684d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(stateMachine.getFrequencyBand()).thenReturn(1);
19784d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(stateMachine.isLinkDebouncing()).thenReturn(false);
19884d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(stateMachine.isConnected()).thenReturn(false);
19984d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(stateMachine.isDisconnected()).thenReturn(true);
20084d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(stateMachine.isSupplicantTransientState()).thenReturn(false);
20184d962ec8f487f824214744498bba505a6db0c59Randy Pan
20284d962ec8f487f824214744498bba505a6db0c59Randy Pan        return stateMachine;
20384d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
20484d962ec8f487f824214744498bba505a6db0c59Randy Pan
20509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    WifiQualifiedNetworkSelector mockWifiQualifiedNetworkSelector() {
20684d962ec8f487f824214744498bba505a6db0c59Randy Pan        WifiQualifiedNetworkSelector qns = mock(WifiQualifiedNetworkSelector.class);
20784d962ec8f487f824214744498bba505a6db0c59Randy Pan
20884d962ec8f487f824214744498bba505a6db0c59Randy Pan        WifiConfiguration candidate = generateWifiConfig(
20984d962ec8f487f824214744498bba505a6db0c59Randy Pan                0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
21084d962ec8f487f824214744498bba505a6db0c59Randy Pan        candidate.BSSID = CANDIDATE_BSSID;
21184d962ec8f487f824214744498bba505a6db0c59Randy Pan        ScanResult candidateScanResult = new ScanResult();
21284d962ec8f487f824214744498bba505a6db0c59Randy Pan        candidateScanResult.SSID = CANDIDATE_SSID;
21384d962ec8f487f824214744498bba505a6db0c59Randy Pan        candidateScanResult.BSSID = CANDIDATE_BSSID;
21484d962ec8f487f824214744498bba505a6db0c59Randy Pan        candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult);
21584d962ec8f487f824214744498bba505a6db0c59Randy Pan
21684d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(qns.selectQualifiedNetwork(anyBoolean(), anyBoolean(), anyObject(),
21784d962ec8f487f824214744498bba505a6db0c59Randy Pan              anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(candidate);
21884d962ec8f487f824214744498bba505a6db0c59Randy Pan        return qns;
21984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
22084d962ec8f487f824214744498bba505a6db0c59Randy Pan
221fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    WifiInfo getWifiInfo() {
222fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        WifiInfo wifiInfo = new WifiInfo();
22384d962ec8f487f824214744498bba505a6db0c59Randy Pan
224fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        wifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
225fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        wifiInfo.setBSSID(null);
226fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        wifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
22784d962ec8f487f824214744498bba505a6db0c59Randy Pan
22884d962ec8f487f824214744498bba505a6db0c59Randy Pan        return wifiInfo;
22984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
23084d962ec8f487f824214744498bba505a6db0c59Randy Pan
23109abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    WifiConfigManager mockWifiConfigManager() {
23284d962ec8f487f824214744498bba505a6db0c59Randy Pan        WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
23384d962ec8f487f824214744498bba505a6db0c59Randy Pan
23484d962ec8f487f824214744498bba505a6db0c59Randy Pan        when(wifiConfigManager.getWifiConfiguration(anyInt())).thenReturn(null);
235a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        when(wifiConfigManager.getEnableAutoJoinWhenAssociated()).thenReturn(true);
23673a52d3336a40903965b946f6d3624a223ad5aacSamuel Tan        wifiConfigManager.mThresholdSaturatedRssi24 = new AtomicInteger(
23784d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiQualifiedNetworkSelector.RSSI_SATURATION_2G_BAND);
23873a52d3336a40903965b946f6d3624a223ad5aacSamuel Tan        wifiConfigManager.mCurrentNetworkBoost = new AtomicInteger(
23984d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiQualifiedNetworkSelector.SAME_NETWORK_AWARD);
24084d962ec8f487f824214744498bba505a6db0c59Randy Pan
241fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Pass dummy pno network list, otherwise Pno scan requests will not be triggered.
242fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        PnoSettings.PnoNetwork pnoNetwork = new PnoSettings.PnoNetwork(CANDIDATE_SSID);
243fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = new ArrayList<>();
244fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        pnoNetworkList.add(pnoNetwork);
245fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        when(wifiConfigManager.retrieveDisconnectedPnoNetworkList()).thenReturn(pnoNetworkList);
246fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        when(wifiConfigManager.retrieveConnectedPnoNetworkList()).thenReturn(pnoNetworkList);
247fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
24884d962ec8f487f824214744498bba505a6db0c59Randy Pan        return wifiConfigManager;
24984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
25084d962ec8f487f824214744498bba505a6db0c59Randy Pan
25109abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    WifiInjector mockWifiInjector() {
25209abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        WifiInjector wifiInjector = mock(WifiInjector.class);
25309abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        mWifiLastResortWatchdog = mock(WifiLastResortWatchdog.class);
2541d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mWifiMetrics = mock(WifiMetrics.class);
25509abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        when(wifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog);
2561d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        when(wifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
257fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        when(wifiInjector.getClock()).thenReturn(mClock);
25809abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne        return wifiInjector;
25909abbe29be6e552a2531b0367bd6d29647d33767Glen Kuhne    }
26084d962ec8f487f824214744498bba505a6db0c59Randy Pan
26184d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
26284d962ec8f487f824214744498bba505a6db0c59Randy Pan     *  Wifi enters disconnected state while screen is on.
26384d962ec8f487f824214744498bba505a6db0c59Randy Pan     *
26484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Expected behavior: WifiConnectivityManager calls
26584d962ec8f487f824214744498bba505a6db0c59Randy Pan     * WifiStateMachine.autoConnectToNetwork() with the
26684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * expected candidate network ID and BSSID.
26784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
26884d962ec8f487f824214744498bba505a6db0c59Randy Pan    @Test
26984d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void enterWifiDisconnectedStateWhenScreenOn() {
27084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set screen to on
27184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
27284d962ec8f487f824214744498bba505a6db0c59Randy Pan
27384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set WiFi to disconnected state
27484d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
27584d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
27684d962ec8f487f824214744498bba505a6db0c59Randy Pan
27784d962ec8f487f824214744498bba505a6db0c59Randy Pan        verify(mWifiStateMachine).autoConnectToNetwork(
27884d962ec8f487f824214744498bba505a6db0c59Randy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
27984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
28084d962ec8f487f824214744498bba505a6db0c59Randy Pan
28184d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
28284d962ec8f487f824214744498bba505a6db0c59Randy Pan     *  Wifi enters connected state while screen is on.
28384d962ec8f487f824214744498bba505a6db0c59Randy Pan     *
28484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Expected behavior: WifiConnectivityManager calls
28584d962ec8f487f824214744498bba505a6db0c59Randy Pan     * WifiStateMachine.autoConnectToNetwork() with the
28684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * expected candidate network ID and BSSID.
28784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
28884d962ec8f487f824214744498bba505a6db0c59Randy Pan    @Test
28984d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void enterWifiConnectedStateWhenScreenOn() {
29084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set screen to on
29184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
29284d962ec8f487f824214744498bba505a6db0c59Randy Pan
29384d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set WiFi to connected state
29484d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
29584d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiConnectivityManager.WIFI_STATE_CONNECTED);
29684d962ec8f487f824214744498bba505a6db0c59Randy Pan
29784d962ec8f487f824214744498bba505a6db0c59Randy Pan        verify(mWifiStateMachine).autoConnectToNetwork(
29884d962ec8f487f824214744498bba505a6db0c59Randy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
29984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
30084d962ec8f487f824214744498bba505a6db0c59Randy Pan
30184d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
30284d962ec8f487f824214744498bba505a6db0c59Randy Pan     *  Screen turned on while WiFi in disconnected state.
30384d962ec8f487f824214744498bba505a6db0c59Randy Pan     *
30484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Expected behavior: WifiConnectivityManager calls
30584d962ec8f487f824214744498bba505a6db0c59Randy Pan     * WifiStateMachine.autoConnectToNetwork() with the
30684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * expected candidate network ID and BSSID.
30784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
30884d962ec8f487f824214744498bba505a6db0c59Randy Pan    @Test
30984d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void turnScreenOnWhenWifiInDisconnectedState() {
31084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set WiFi to disconnected state
31184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
31284d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
31384d962ec8f487f824214744498bba505a6db0c59Randy Pan
31484d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set screen to on
31584d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
31684d962ec8f487f824214744498bba505a6db0c59Randy Pan
317fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        verify(mWifiStateMachine, atLeastOnce()).autoConnectToNetwork(
31884d962ec8f487f824214744498bba505a6db0c59Randy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
31984d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
32084d962ec8f487f824214744498bba505a6db0c59Randy Pan
32184d962ec8f487f824214744498bba505a6db0c59Randy Pan    /**
32284d962ec8f487f824214744498bba505a6db0c59Randy Pan     *  Screen turned on while WiFi in connected state.
32384d962ec8f487f824214744498bba505a6db0c59Randy Pan     *
32484d962ec8f487f824214744498bba505a6db0c59Randy Pan     * Expected behavior: WifiConnectivityManager calls
32584d962ec8f487f824214744498bba505a6db0c59Randy Pan     * WifiStateMachine.autoConnectToNetwork() with the
32684d962ec8f487f824214744498bba505a6db0c59Randy Pan     * expected candidate network ID and BSSID.
32784d962ec8f487f824214744498bba505a6db0c59Randy Pan     */
32884d962ec8f487f824214744498bba505a6db0c59Randy Pan    @Test
32984d962ec8f487f824214744498bba505a6db0c59Randy Pan    public void turnScreenOnWhenWifiInConnectedState() {
33084d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set WiFi to connected state
33184d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
33284d962ec8f487f824214744498bba505a6db0c59Randy Pan                WifiConnectivityManager.WIFI_STATE_CONNECTED);
33384d962ec8f487f824214744498bba505a6db0c59Randy Pan
33484d962ec8f487f824214744498bba505a6db0c59Randy Pan        // Set screen to on
33584d962ec8f487f824214744498bba505a6db0c59Randy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
33684d962ec8f487f824214744498bba505a6db0c59Randy Pan
337fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        verify(mWifiStateMachine, atLeastOnce()).autoConnectToNetwork(
338fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
339fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    }
340fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
341fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    /**
342a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan     *  Screen turned on while WiFi in connected state but
343a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan     *  auto roaming is disabled.
344a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan     *
345a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan     * Expected behavior: WifiConnectivityManager doesn't invoke
346a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan     * WifiStateMachine.autoConnectToNetwork() because roaming
347a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan     * is turned off.
348a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan     */
349a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan    @Test
350a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan    public void turnScreenOnWhenWifiInConnectedStateRoamingDisabled() {
351a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        // Set WiFi to connected state
352a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
353a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan                WifiConnectivityManager.WIFI_STATE_CONNECTED);
354a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan
355a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        // Turn off auto roaming
356a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        when(mWifiConfigManager.getEnableAutoJoinWhenAssociated()).thenReturn(false);
357a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan
358a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        // Set screen to on
359a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
360a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan
361a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan        verify(mWifiStateMachine, times(0)).autoConnectToNetwork(
362a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
363a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan    }
364a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan
365a68f3e359ac27285b10332ea2461469e5e03bfd4Randy Pan    /**
366fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * Multiple back to back connection attempts within the rate interval should be rate limited.
367fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     *
368fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * Expected behavior: WifiConnectivityManager calls WifiStateMachine.autoConnectToNetwork()
369fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * with the expected candidate network ID and BSSID for only the expected number of times within
370fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * the given interval.
371fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     */
372fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    @Test
373fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    public void connectionAttemptRateLimitedWhenScreenOff() {
374fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
375fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
376fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int numAttempts = 0;
377fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int connectionAttemptIntervals = timeInterval / maxAttemptRate;
378fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
379fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mWifiConnectivityManager.handleScreenStateChanged(false);
380fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
381fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // First attempt the max rate number of connections within the rate interval.
382fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        long currentTimeStamp = 0;
383fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
384fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            currentTimeStamp += connectionAttemptIntervals;
385ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
386fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            // Set WiFi to disconnected state to trigger PNO scan
387fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            mWifiConnectivityManager.handleConnectionStateChanged(
388fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
389fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            numAttempts++;
390fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        }
391fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Now trigger another connection attempt before the rate interval, this should be
392fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // skipped because we've crossed rate limit.
393ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
394fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Set WiFi to disconnected state to trigger PNO scan
395fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mWifiConnectivityManager.handleConnectionStateChanged(
396fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
397fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
398fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Verify that we attempt to connect upto the rate.
399fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        verify(mWifiStateMachine, times(numAttempts)).autoConnectToNetwork(
400fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
401fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    }
402fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
403fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    /**
404fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * Multiple back to back connection attempts outside the rate interval should not be rate
405fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * limited.
406fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     *
407fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * Expected behavior: WifiConnectivityManager calls WifiStateMachine.autoConnectToNetwork()
408fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * with the expected candidate network ID and BSSID for only the expected number of times within
409fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * the given interval.
410fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     */
411fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    @Test
412fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    public void connectionAttemptNotRateLimitedWhenScreenOff() {
413fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
414fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
415fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int numAttempts = 0;
416fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int connectionAttemptIntervals = timeInterval / maxAttemptRate;
417fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
418fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mWifiConnectivityManager.handleScreenStateChanged(false);
419fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
420fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // First attempt the max rate number of connections within the rate interval.
421fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        long currentTimeStamp = 0;
422fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
423fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            currentTimeStamp += connectionAttemptIntervals;
424ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
425fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            // Set WiFi to disconnected state to trigger PNO scan
426fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            mWifiConnectivityManager.handleConnectionStateChanged(
427fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
428fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            numAttempts++;
429fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        }
430fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Now trigger another connection attempt after the rate interval, this should not be
431fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // skipped because we should've evicted the older attempt.
432ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius        when(mClock.elapsedRealtime()).thenReturn(
433fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                currentTimeStamp + connectionAttemptIntervals * 2);
434fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Set WiFi to disconnected state to trigger PNO scan
435fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mWifiConnectivityManager.handleConnectionStateChanged(
436fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
437fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        numAttempts++;
438fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
439fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Verify that all the connection attempts went through
440fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        verify(mWifiStateMachine, times(numAttempts)).autoConnectToNetwork(
441fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
442fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    }
443fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
444fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    /**
445fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * Multiple back to back connection attempts after a user selection should not be rate limited.
446fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     *
447fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * Expected behavior: WifiConnectivityManager calls WifiStateMachine.autoConnectToNetwork()
448fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * with the expected candidate network ID and BSSID for only the expected number of times within
449fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     * the given interval.
450fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius     */
451fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    @Test
452fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius    public void connectionAttemptNotRateLimitedWhenScreenOffAfterUserSelection() {
453fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
454fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
455fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int numAttempts = 0;
456fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        int connectionAttemptIntervals = timeInterval / maxAttemptRate;
457fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
458fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mWifiConnectivityManager.handleScreenStateChanged(false);
459fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
460fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // First attempt the max rate number of connections within the rate interval.
461fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        long currentTimeStamp = 0;
462fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
463fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            currentTimeStamp += connectionAttemptIntervals;
464ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
465fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            // Set WiFi to disconnected state to trigger PNO scan
466fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            mWifiConnectivityManager.handleConnectionStateChanged(
467fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
468fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            numAttempts++;
469fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        }
470fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
471fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        mWifiConnectivityManager.connectToUserSelectNetwork(CANDIDATE_NETWORK_ID, false);
472fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
473fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
474fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            currentTimeStamp += connectionAttemptIntervals;
475ee0ab818341d44614ffe56ae73ecc08b974c2cbbRoshan Pius            when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
476fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            // Set WiFi to disconnected state to trigger PNO scan
477fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            mWifiConnectivityManager.handleConnectionStateChanged(
478fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius                    WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
479fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius            numAttempts++;
480fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        }
481fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius
482fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        // Verify that all the connection attempts went through
483fa2ac2743307559e8dcc5aaf54873536315fbe62Roshan Pius        verify(mWifiStateMachine, times(numAttempts)).autoConnectToNetwork(
48484d962ec8f487f824214744498bba505a6db0c59Randy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
48584d962ec8f487f824214744498bba505a6db0c59Randy Pan    }
4863d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
4873d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    /**
4883d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     *  PNO retry for low RSSI networks.
4893d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     *
4903d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     * Expected behavior: WifiConnectivityManager doubles the low RSSI
4913d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     * network retry delay value after QNS skips the PNO scan results
4923d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     * because of their low RSSI values.
4933d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan     */
4943d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    @Test
4953d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    public void PnoRetryForLowRssiNetwork() {
4963d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        when(mWifiQNS.selectQualifiedNetwork(anyBoolean(), anyBoolean(), anyObject(),
4973d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan              anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(null);
4983d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
4993d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // Set screen to off
5003d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        mWifiConnectivityManager.handleScreenStateChanged(false);
5013d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
5023d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // Get the current retry delay value
5033d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        int lowRssiNetworkRetryDelayStartValue = mWifiConnectivityManager
5043d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                .getLowRssiNetworkRetryDelay();
5053d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
5063d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // Set WiFi to disconnected state to trigger PNO scan
5073d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
5083d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
5093d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
5103d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // Get the retry delay value after QNS didn't select a
5113d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        // network candicate from the PNO scan results.
5123d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        int lowRssiNetworkRetryDelayAfterPnoValue = mWifiConnectivityManager
5133d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan                .getLowRssiNetworkRetryDelay();
5143d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan
5153d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan        assertEquals(lowRssiNetworkRetryDelayStartValue * 2,
5163d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan            lowRssiNetworkRetryDelayAfterPnoValue);
5173d09b9117df33608a43c1fbe0135123e2de9aea2Randy Pan    }
5181d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5191d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    /**
5201d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     * Ensure that the watchdog bite increments the "Pno bad" metric.
5211d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     *
5221d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     * Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find
5231d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     * a candidate while watchdog single scan did.
5241d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     */
5251d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    @Test
5261d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    public void watchdogBitePnoBadIncrementsMetrics() {
5271d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        // Set screen to off
5281d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mWifiConnectivityManager.handleScreenStateChanged(false);
5291d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5301d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        // Set WiFi to disconnected state to trigger PNO scan
5311d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mWifiConnectivityManager.handleConnectionStateChanged(
5321d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
5331d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5341d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        // Now fire the watchdog alarm and verify the metrics were incremented.
5351d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG);
5361d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mLooper.dispatchAll();
5371d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5381d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoBad();
5391d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoGood();
5401d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    }
5411d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5421d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    /**
5431d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     * Ensure that the watchdog bite increments the "Pno good" metric.
5441d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     *
5451d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     * Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find
5461d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     * a candidate which was the same with watchdog single scan.
5471d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius     */
5481d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    @Test
5491d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    public void watchdogBitePnoGoodIncrementsMetrics() {
5501d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        // Qns returns no candidate after watchdog single scan.
5511d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        when(mWifiQNS.selectQualifiedNetwork(anyBoolean(), anyBoolean(), anyObject(),
5521d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(null);
5531d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5541d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        // Set screen to off
5551d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mWifiConnectivityManager.handleScreenStateChanged(false);
5561d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5571d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        // Set WiFi to disconnected state to trigger PNO scan
5581d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mWifiConnectivityManager.handleConnectionStateChanged(
5591d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
5601d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5611d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        // Now fire the watchdog alarm and verify the metrics were incremented.
5621d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG);
5631d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        mLooper.dispatchAll();
5641d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius
5651d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoGood();
5661d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius        verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoBad();
5671d7d62393181cc36b6f87c3cf2151adc54275f9cRoshan Pius    }
568b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
569b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    /**
570b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     *  Verify that scan interval for screen on and wifi disconnected scenario
571b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     *  is in the exponential backoff fashion.
572b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     *
573b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     * Expected behavior: WifiConnectivityManager doubles periodic
574b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     * scan interval.
575b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     */
576b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    @Test
577b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    public void checkPeriodicScanIntervalWhenDisconnected() {
578c2963eb07660a06592c60224279685166390217dRandy Pan        long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
579c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
580b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
581b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Set screen to ON
582b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
583b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
584c2963eb07660a06592c60224279685166390217dRandy Pan        // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered
585c2963eb07660a06592c60224279685166390217dRandy Pan        // by screen state change can settle
586c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS;
587c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
588c2963eb07660a06592c60224279685166390217dRandy Pan
589b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Set WiFi to disconnected state to trigger periodic scan
590b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
591b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
592b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
593b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Get the first periodic scan interval
594b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        long firstIntervalMs = mAlarmManager
595b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                    .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
596c2963eb07660a06592c60224279685166390217dRandy Pan                    - currentTimeStamp;
597b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS);
598b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
599c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += firstIntervalMs;
600c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
601c2963eb07660a06592c60224279685166390217dRandy Pan
602b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Now fire the first periodic scan alarm timer
603b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
604b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mLooper.dispatchAll();
605b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
606b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Get the second periodic scan interval
607b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        long secondIntervalMs = mAlarmManager
608b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                    .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
609c2963eb07660a06592c60224279685166390217dRandy Pan                    - currentTimeStamp;
610b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
611b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Verify the intervals are exponential back off
612b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        assertEquals(firstIntervalMs * 2, secondIntervalMs);
613b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
614c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += secondIntervalMs;
615c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
616c2963eb07660a06592c60224279685166390217dRandy Pan
617b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Make sure we eventually stay at the maximum scan interval.
618b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        long intervalMs = 0;
619b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        for (int i = 0; i < 5; i++) {
620b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan            mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
621b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan            mLooper.dispatchAll();
622b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan            intervalMs = mAlarmManager
623b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                    .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
624c2963eb07660a06592c60224279685166390217dRandy Pan                    - currentTimeStamp;
625c2963eb07660a06592c60224279685166390217dRandy Pan            currentTimeStamp += intervalMs;
626c2963eb07660a06592c60224279685166390217dRandy Pan            when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
627b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        }
628b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
629b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        assertEquals(intervalMs, WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS);
630b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    }
631b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
632b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    /**
633b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     *  Verify that scan interval for screen on and wifi connected scenario
634b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     *  is in the exponential backoff fashion.
635b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     *
636b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     * Expected behavior: WifiConnectivityManager doubles periodic
637b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     * scan interval.
638b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan     */
639b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    @Test
640b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    public void checkPeriodicScanIntervalWhenConnected() {
641c2963eb07660a06592c60224279685166390217dRandy Pan        long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
642c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
643b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
644b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Set screen to ON
645b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
646b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
647c2963eb07660a06592c60224279685166390217dRandy Pan        // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered
648c2963eb07660a06592c60224279685166390217dRandy Pan        // by screen state change can settle
649c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS;
650c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
651c2963eb07660a06592c60224279685166390217dRandy Pan
652b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Set WiFi to connected state to trigger periodic scan
653b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
654b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                WifiConnectivityManager.WIFI_STATE_CONNECTED);
655b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
656b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Get the first periodic scan interval
657b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        long firstIntervalMs = mAlarmManager
658b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                    .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
659c2963eb07660a06592c60224279685166390217dRandy Pan                    - currentTimeStamp;
660b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS);
661b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
662c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += firstIntervalMs;
663c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
664c2963eb07660a06592c60224279685166390217dRandy Pan
665b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Now fire the first periodic scan alarm timer
666b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
667b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        mLooper.dispatchAll();
668b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
669b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Get the second periodic scan interval
670b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        long secondIntervalMs = mAlarmManager
671b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                    .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
672c2963eb07660a06592c60224279685166390217dRandy Pan                    - currentTimeStamp;
673b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
674b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Verify the intervals are exponential back off
675b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        assertEquals(firstIntervalMs * 2, secondIntervalMs);
676b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
677c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += secondIntervalMs;
678c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
679c2963eb07660a06592c60224279685166390217dRandy Pan
680b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        // Make sure we eventually stay at the maximum scan interval.
681b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        long intervalMs = 0;
682b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        for (int i = 0; i < 5; i++) {
683b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan            mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
684b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan            mLooper.dispatchAll();
685b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan            intervalMs = mAlarmManager
686b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan                    .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
687c2963eb07660a06592c60224279685166390217dRandy Pan                    - currentTimeStamp;
688c2963eb07660a06592c60224279685166390217dRandy Pan            currentTimeStamp += intervalMs;
689c2963eb07660a06592c60224279685166390217dRandy Pan            when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
690b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        }
691b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan
692b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan        assertEquals(intervalMs, WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS);
693b32b649c815b0b50fd0127d9d4a4563c54a536fbRandy Pan    }
694fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
695fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    /**
696c2963eb07660a06592c60224279685166390217dRandy Pan     *  When screen on trigger two connection state change events back to back to
697c2963eb07660a06592c60224279685166390217dRandy Pan     *  verify that the minium scan interval is enforced.
698c2963eb07660a06592c60224279685166390217dRandy Pan     *
699c2963eb07660a06592c60224279685166390217dRandy Pan     * Expected behavior: WifiConnectivityManager start the second periodic single
700c2963eb07660a06592c60224279685166390217dRandy Pan     * scan PERIODIC_SCAN_INTERVAL_MS after the first one.
701c2963eb07660a06592c60224279685166390217dRandy Pan     */
702c2963eb07660a06592c60224279685166390217dRandy Pan    @Test
703c2963eb07660a06592c60224279685166390217dRandy Pan    public void checkMinimumPeriodicScanIntervalWhenScreenOn() {
704c2963eb07660a06592c60224279685166390217dRandy Pan        long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
705c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
706c2963eb07660a06592c60224279685166390217dRandy Pan
707c2963eb07660a06592c60224279685166390217dRandy Pan        // Set screen to ON
708c2963eb07660a06592c60224279685166390217dRandy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
709c2963eb07660a06592c60224279685166390217dRandy Pan
710c2963eb07660a06592c60224279685166390217dRandy Pan        // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered
711c2963eb07660a06592c60224279685166390217dRandy Pan        // by screen state change can settle
712c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS;
713c2963eb07660a06592c60224279685166390217dRandy Pan        long firstScanTimeStamp = currentTimeStamp;
714c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
715c2963eb07660a06592c60224279685166390217dRandy Pan
716c2963eb07660a06592c60224279685166390217dRandy Pan        // Set WiFi to connected state to trigger the periodic scan
717c2963eb07660a06592c60224279685166390217dRandy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
718c2963eb07660a06592c60224279685166390217dRandy Pan                WifiConnectivityManager.WIFI_STATE_CONNECTED);
719c2963eb07660a06592c60224279685166390217dRandy Pan
720c2963eb07660a06592c60224279685166390217dRandy Pan        // Set the second scan attempt time stamp.
721c2963eb07660a06592c60224279685166390217dRandy Pan        currentTimeStamp += 2000;
722c2963eb07660a06592c60224279685166390217dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
723c2963eb07660a06592c60224279685166390217dRandy Pan
724c2963eb07660a06592c60224279685166390217dRandy Pan        // Set WiFi to disconnected state to trigger another periodic scan
725c2963eb07660a06592c60224279685166390217dRandy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
726c2963eb07660a06592c60224279685166390217dRandy Pan                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
727c2963eb07660a06592c60224279685166390217dRandy Pan
728c2963eb07660a06592c60224279685166390217dRandy Pan        // Get the second periodic scan actual time stamp
729c2963eb07660a06592c60224279685166390217dRandy Pan        long secondScanTimeStamp = mAlarmManager
730c2963eb07660a06592c60224279685166390217dRandy Pan                    .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
731c2963eb07660a06592c60224279685166390217dRandy Pan
732c2963eb07660a06592c60224279685166390217dRandy Pan        // Verify that the second scan is scheduled PERIODIC_SCAN_INTERVAL_MS after the
733c2963eb07660a06592c60224279685166390217dRandy Pan        // very first scan.
734c2963eb07660a06592c60224279685166390217dRandy Pan        assertEquals(secondScanTimeStamp, firstScanTimeStamp
735c2963eb07660a06592c60224279685166390217dRandy Pan                       + WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS);
736c2963eb07660a06592c60224279685166390217dRandy Pan
737c2963eb07660a06592c60224279685166390217dRandy Pan    }
738c2963eb07660a06592c60224279685166390217dRandy Pan
739c2963eb07660a06592c60224279685166390217dRandy Pan    /**
740016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan     *  When screen on trigger a connection state change event and a forced connectivity
741016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan     *  scan event back to back to verify that the minimum scan interval is not applied
742016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan     *  in this scenario.
743016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan     *
744016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan     * Expected behavior: WifiConnectivityManager starts the second periodic single
745016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan     * scan immediately.
746016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan     */
747016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    @Test
748016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    public void checkMinimumPeriodicScanIntervalNotEnforced() {
749016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
750016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
751016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
752016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // Set screen to ON
753016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
754016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
755016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered
756016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // by screen state change can settle
757016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS;
758016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        long firstScanTimeStamp = currentTimeStamp;
759016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
760016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
761016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // Set WiFi to connected state to trigger the periodic scan
762016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
763016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan                WifiConnectivityManager.WIFI_STATE_CONNECTED);
764016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
765016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // Set the second scan attempt time stamp
766016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        currentTimeStamp += 2000;
767016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
768016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
7698cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // Allow untrusted networks so WifiConnectivityManager starts a periodic scan
7708cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // immediately.
7718cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
772016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
773016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // Get the second periodic scan actual time stamp. Note, this scan is not
774016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // started from the AlarmManager.
775016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        long secondScanTimeStamp = mWifiConnectivityManager.getLastPeriodicSingleScanTimeStamp();
776016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
777016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        // Verify that the second scan is fired immediately
778016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan        assertEquals(secondScanTimeStamp, currentTimeStamp);
779016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    }
780016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan
781016ca1ae5e33eb9529ae10c2510a56fa5c7fec4dRandy Pan    /**
782fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * Verify that we perform full band scan when the currently connected network's tx/rx success
783fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * rate is low.
784fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     *
785fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * Expected behavior: WifiConnectivityManager does full band scan.
786fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     */
787fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    @Test
788fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    public void checkSingleScanSettingsWhenConnectedWithLowDataRate() {
789fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiInfo.txSuccessRate = 0;
790fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiInfo.rxSuccessRate = 0;
791fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
792fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        final HashSet<Integer> channelList = new HashSet<>();
793fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        channelList.add(1);
794fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        channelList.add(2);
795fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        channelList.add(3);
796fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
797fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiStateMachine.getCurrentWifiConfiguration())
798fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(new WifiConfiguration());
799fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiStateMachine.getFrequencyBand())
800fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(WifiManager.WIFI_FREQUENCY_BAND_5GHZ);
801fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiConfigManager.makeChannelList(any(WifiConfiguration.class), anyInt()))
802fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(channelList);
803fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
804fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        doAnswer(new AnswerWithArguments() {
805fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            public void answer(ScanSettings settings, ScanListener listener,
806fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                    WorkSource workSource) throws Exception {
807fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                assertEquals(settings.band, WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS);
808fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                assertNull(settings.channels);
809fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
810fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
811fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        // Set screen to ON
812fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiConnectivityManager.handleScreenStateChanged(true);
813fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
814fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        // Set WiFi to connected state to trigger periodic scan
815fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiConnectivityManager.handleConnectionStateChanged(
816fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                WifiConnectivityManager.WIFI_STATE_CONNECTED);
817fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
818fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
819fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    }
820fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
821fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    /**
822fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * Verify that we perform partial scan when the currently connected network's tx/rx success
823fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * rate is high and when the currently connected network is present in scan
824fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * cache in WifiConfigManager.
825fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     *
826fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * Expected behavior: WifiConnectivityManager does full band scan.
827fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     */
828fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    @Test
829fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    public void checkSingleScanSettingsWhenConnectedWithHighDataRate() {
830fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiInfo.txSuccessRate = WifiConfigManager.MAX_TX_PACKET_FOR_FULL_SCANS * 2;
831fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiInfo.rxSuccessRate = WifiConfigManager.MAX_RX_PACKET_FOR_FULL_SCANS * 2;
832fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
833fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        final HashSet<Integer> channelList = new HashSet<>();
834fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        channelList.add(1);
835fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        channelList.add(2);
836fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        channelList.add(3);
837fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
838fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiStateMachine.getCurrentWifiConfiguration())
839fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(new WifiConfiguration());
840fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiConfigManager.makeChannelList(any(WifiConfiguration.class), anyInt()))
841fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(channelList);
842fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
843fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        doAnswer(new AnswerWithArguments() {
844fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            public void answer(ScanSettings settings, ScanListener listener,
845fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                    WorkSource workSource) throws Exception {
846fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                assertEquals(settings.band, WifiScanner.WIFI_BAND_UNSPECIFIED);
847fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                assertEquals(settings.channels.length, channelList.size());
848fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                for (int chanIdx = 0; chanIdx < settings.channels.length; chanIdx++) {
849fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                    assertTrue(channelList.contains(settings.channels[chanIdx].frequency));
850fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                }
851fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
852fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
853fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        // Set screen to ON
854fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiConnectivityManager.handleScreenStateChanged(true);
855fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
856fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        // Set WiFi to connected state to trigger periodic scan
857fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiConnectivityManager.handleConnectionStateChanged(
858fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                WifiConnectivityManager.WIFI_STATE_CONNECTED);
859fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
860fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
861fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    }
862fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
863fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    /**
864fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * Verify that we fall back to full band scan when the currently connected network's tx/rx
865fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * success rate is high and the currently connected network is not present in scan cache in
866fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * WifiConfigManager. This is simulated by returning an empty hashset in |makeChannelList|.
867fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     *
868fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     * Expected behavior: WifiConnectivityManager does full band scan.
869fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius     */
870fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    @Test
871fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    public void checkSingleScanSettingsWhenConnectedWithHighDataRateNotInCache() {
872fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiInfo.txSuccessRate = WifiConfigManager.MAX_TX_PACKET_FOR_FULL_SCANS * 2;
873fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiInfo.rxSuccessRate = WifiConfigManager.MAX_RX_PACKET_FOR_FULL_SCANS * 2;
874fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
875fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        final HashSet<Integer> channelList = new HashSet<>();
876fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
877fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiStateMachine.getCurrentWifiConfiguration())
878fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(new WifiConfiguration());
879fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiStateMachine.getFrequencyBand())
880fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(WifiManager.WIFI_FREQUENCY_BAND_5GHZ);
881fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        when(mWifiConfigManager.makeChannelList(any(WifiConfiguration.class), anyInt()))
882fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                .thenReturn(channelList);
883fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
884fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        doAnswer(new AnswerWithArguments() {
885fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            public void answer(ScanSettings settings, ScanListener listener,
886fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                    WorkSource workSource) throws Exception {
887fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                assertEquals(settings.band, WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS);
888fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                assertNull(settings.channels);
889fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius            }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
890fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
891fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        // Set screen to ON
892fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiConnectivityManager.handleScreenStateChanged(true);
893fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
894fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        // Set WiFi to connected state to trigger periodic scan
895fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        mWifiConnectivityManager.handleConnectionStateChanged(
896fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius                WifiConnectivityManager.WIFI_STATE_CONNECTED);
897fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius
898fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius        verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
899fb196453c07daad5e525520cecad84cec5d89fb7Roshan Pius    }
900de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan
901de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan    /**
902de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan     *  Verify that we retry connectivity scan up to MAX_SCAN_RESTART_ALLOWED times
903de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan     *  when Wifi somehow gets into a bad state and fails to scan.
904de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan     *
905de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan     * Expected behavior: WifiConnectivityManager schedules connectivity scan
906de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan     * MAX_SCAN_RESTART_ALLOWED times.
907de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan     */
908de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan    @Test
909de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan    public void checkMaximumScanRetry() {
910de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        // Set screen to ON
911de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        mWifiConnectivityManager.handleScreenStateChanged(true);
912de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan
913de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        doAnswer(new AnswerWithArguments() {
914de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan            public void answer(ScanSettings settings, ScanListener listener,
915de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan                    WorkSource workSource) throws Exception {
916de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan                listener.onFailure(-1, "ScanFailure");
917de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan            }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
918de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan
919de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        // Set WiFi to disconnected state to trigger the single scan based periodic scan
920de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
921de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
922de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan
923de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        // Fire the alarm timer 2x timers
924de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        for (int i = 0; i < (WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED * 2); i++) {
925de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan            mAlarmManager.dispatch(WifiConnectivityManager.RESTART_SINGLE_SCAN_TIMER_TAG);
926de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan            mLooper.dispatchAll();
927de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        }
928de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan
929de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        // Verify that the connectivity scan has been retried for MAX_SCAN_RESTART_ALLOWED
930de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        // times. Note, WifiScanner.startScan() is invoked MAX_SCAN_RESTART_ALLOWED + 1 times.
931de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        // The very first scan is the initial one, and the other MAX_SCAN_RESTART_ALLOWED
932de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        // are the retrial ones.
933de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan        verify(mWifiScanner, times(WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED + 1)).startScan(
934de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan                anyObject(), anyObject(), anyObject());
935de5fadf2e5c7bb769705c830efb04133b1e0219dRandy Pan    }
936cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan
937cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan    /**
938cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan     * Listen to scan results not requested by WifiConnectivityManager and
939cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan     * act on them.
940cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan     *
941cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan     * Expected behavior: WifiConnectivityManager calls
942cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan     * WifiStateMachine.autoConnectToNetwork() with the
943cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan     * expected candidate network ID and BSSID.
944cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan     */
945cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan    @Test
946cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan    public void listenToAllSingleScanResults() {
947cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        ScanSettings settings = new ScanSettings();
948cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        ScanListener scanListener = mock(ScanListener.class);
949cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan
950cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        // Request a single scan outside of WifiConnectivityManager.
951cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        mWifiScanner.startScan(settings, scanListener, WIFI_WORK_SOURCE);
952cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan
953cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        // Verify that WCM receives the scan results and initiates a connection
954cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        // to the network.
955cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan        verify(mWifiStateMachine).autoConnectToNetwork(
956cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
957cb26f07ae9c558f8c6136c951a7f633d0ccfe79fRandy Pan    }
9588cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
9598cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan    /**
9608cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan     *  Verify that a forced connectivity scan waits for full band scan
9618cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan     *  results.
9628cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan     *
9638cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan     * Expected behavior: WifiConnectivityManager doesn't invoke
9648cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan     * WifiStateMachine.autoConnectToNetwork() when full band scan
9658cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan     * results are not available.
9668cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan     */
9678cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan    @Test
9688cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan    public void waitForFullBandScanResults() {
9698cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // Set WiFi to connected state.
9708cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        mWifiConnectivityManager.handleConnectionStateChanged(
9718cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan                WifiConnectivityManager.WIFI_STATE_CONNECTED);
9728cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
9738cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // Set up as partial scan results.
9748cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        when(mScanData.isAllChannelsScanned()).thenReturn(false);
9758cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
9768cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // Force a connectivity scan which enables WifiConnectivityManager
9778cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // to wait for full band scan results.
9788cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        mWifiConnectivityManager.forceConnectivityScan();
9798cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
9808cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // No roaming because no full band scan results.
9818cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        verify(mWifiStateMachine, times(0)).autoConnectToNetwork(
9828cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
9838cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
9848cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // Set up as full band scan results.
9858cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        when(mScanData.isAllChannelsScanned()).thenReturn(true);
9868cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
9878cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // Force a connectivity scan which enables WifiConnectivityManager
9888cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // to wait for full band scan results.
9898cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        mWifiConnectivityManager.forceConnectivityScan();
9908cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan
9918cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        // Roaming attempt because full band scan results are available.
9928cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan        verify(mWifiStateMachine).autoConnectToNetwork(
9938cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
9948cf5bfbee9d70dac8c83729a979bd7208a47d44dRandy Pan    }
99584d962ec8f487f824214744498bba505a6db0c59Randy Pan}
996