blob: 0c49bb66a40e7649d67c69cc31a41739a6c36851 [file] [log] [blame]
Ajay Nadathur7d176bc2016-10-24 16:55:24 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16package com.android.settingslib.wifi;
17
Sundeep Ghuman2b489902017-02-22 18:17:29 -080018import static com.google.common.truth.Truth.assertThat;
19
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080020import static org.junit.Assert.assertEquals;
Stephen Chen21f68682017-04-04 13:23:31 -070021import static org.junit.Assert.assertFalse;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070022import static org.junit.Assert.assertTrue;
Sundeep Ghuman71f4a822017-04-18 19:51:46 -070023import static org.junit.Assert.fail;
Peter Qiuf5628382017-03-28 13:24:34 -070024import static org.mockito.Mockito.any;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080025import static org.mockito.Mockito.anyInt;
Sundeep Ghuman71f4a822017-04-18 19:51:46 -070026import static org.mockito.Mockito.atMost;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080027import static org.mockito.Mockito.doAnswer;
28import static org.mockito.Mockito.doNothing;
Peter Qiuf5628382017-03-28 13:24:34 -070029import static org.mockito.Mockito.doThrow;
Sundeep Ghumance6bab82017-04-19 16:21:46 -070030import static org.mockito.Mockito.mock;
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -070031import static org.mockito.Mockito.never;
Sundeep Ghuman04f7f342018-01-23 19:18:31 -080032import static org.mockito.Mockito.reset;
Sundeep Ghumance6bab82017-04-19 16:21:46 -070033import static org.mockito.Mockito.times;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080034import static org.mockito.Mockito.verify;
Sundeep Ghuman71f4a822017-04-18 19:51:46 -070035import static org.mockito.Mockito.verifyNoMoreInteractions;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080036import static org.mockito.Mockito.when;
37
38import android.content.Context;
39import android.content.Intent;
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -070040import android.content.IntentFilter;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080041import android.net.ConnectivityManager;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070042import android.net.Network;
Sundeep Ghuman2b489902017-02-22 18:17:29 -080043import android.net.NetworkInfo;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080044import android.net.NetworkKey;
45import android.net.NetworkScoreManager;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080046import android.net.RssiCurve;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070047import android.net.ScoredNetwork;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080048import android.net.WifiKey;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070049import android.net.wifi.ScanResult;
50import android.net.wifi.WifiConfiguration;
Sundeep Ghuman2b489902017-02-22 18:17:29 -080051import android.net.wifi.WifiInfo;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080052import android.net.wifi.WifiManager;
53import android.net.wifi.WifiNetworkScoreCache;
54import android.net.wifi.WifiSsid;
55import android.os.Bundle;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080056import android.os.Handler;
57import android.os.HandlerThread;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070058import android.os.SystemClock;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080059import android.provider.Settings;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070060import android.support.test.InstrumentationRegistry;
Sundeep Ghuman04f7f342018-01-23 19:18:31 -080061import android.support.test.filters.FlakyTest;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070062import android.support.test.filters.SmallTest;
63import android.support.test.runner.AndroidJUnit4;
64
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080065import org.junit.After;
66import org.junit.Before;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070067import org.junit.Test;
68import org.junit.runner.RunWith;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080069import org.mockito.ArgumentCaptor;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080070import org.mockito.Captor;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070071import org.mockito.Matchers;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080072import org.mockito.Mock;
73import org.mockito.MockitoAnnotations;
74import org.mockito.invocation.InvocationOnMock;
75import org.mockito.stubbing.Answer;
76
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070077import java.util.ArrayList;
78import java.util.Arrays;
79import java.util.BitSet;
Sundeep Ghuman04f7f342018-01-23 19:18:31 -080080import java.util.Collections;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070081import java.util.List;
Sundeep Ghuman04f7f342018-01-23 19:18:31 -080082import java.util.Map;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080083import java.util.concurrent.CountDownLatch;
84import java.util.concurrent.TimeUnit;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070085
Sundeep Ghuman2b489902017-02-22 18:17:29 -080086// TODO(sghuman): Change these to robolectric tests b/35766684.
87
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070088@SmallTest
89@RunWith(AndroidJUnit4.class)
90public class WifiTrackerTest {
91
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080092 private static final String TAG = "WifiTrackerTest";
Sundeep Ghumanac7b4362017-02-08 17:19:27 -080093 private static final int LATCH_TIMEOUT = 4000;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080094
95 private static final String SSID_1 = "ssid1";
96 private static final String BSSID_1 = "00:00:00:00:00:00";
97 private static final NetworkKey NETWORK_KEY_1 =
98 new NetworkKey(new WifiKey('"' + SSID_1 + '"', BSSID_1));
99 private static final int RSSI_1 = -30;
100 private static final byte SCORE_1 = 10;
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700101 private static final int BADGE_1 = AccessPoint.Speed.MODERATE;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800102
103 private static final String SSID_2 = "ssid2";
104 private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
105 private static final NetworkKey NETWORK_KEY_2 =
106 new NetworkKey(new WifiKey('"' + SSID_2 + '"', BSSID_2));
107 private static final int RSSI_2 = -30;
108 private static final byte SCORE_2 = 15;
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700109 private static final int BADGE_2 = AccessPoint.Speed.FAST;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800110
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700111 // TODO(b/65594609): Convert mutable Data objects to instance variables / builder pattern
112 private static final int NETWORK_ID_1 = 123;
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700113 private static final int CONNECTED_RSSI = -50;
114 private static final WifiInfo CONNECTED_AP_1_INFO = new WifiInfo();
115 static {
116 CONNECTED_AP_1_INFO.setSSID(WifiSsid.createFromAsciiEncoded(SSID_1));
117 CONNECTED_AP_1_INFO.setBSSID(BSSID_1);
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700118 CONNECTED_AP_1_INFO.setNetworkId(NETWORK_ID_1);
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700119 CONNECTED_AP_1_INFO.setRssi(CONNECTED_RSSI);
120 }
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700121 private static final WifiConfiguration CONFIGURATION_1 = new WifiConfiguration();
122 static {
123 CONFIGURATION_1.SSID = SSID_1;
124 CONFIGURATION_1.BSSID = BSSID_1;
125 CONFIGURATION_1.networkId = NETWORK_ID_1;
126 }
127
128 private static final int NETWORK_ID_2 = 2;
129 private static final WifiConfiguration CONFIGURATION_2 = new WifiConfiguration();
130 static {
131 CONFIGURATION_2.SSID = SSID_2;
132 CONFIGURATION_2.BSSID = BSSID_2;
133 CONFIGURATION_2.networkId = NETWORK_ID_2;
134 }
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700135
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800136 @Captor ArgumentCaptor<WifiNetworkScoreCache> mScoreCacheCaptor;
137 @Mock private ConnectivityManager mockConnectivityManager;
138 @Mock private NetworkScoreManager mockNetworkScoreManager;
139 @Mock private RssiCurve mockCurve1;
140 @Mock private RssiCurve mockCurve2;
141 @Mock private RssiCurve mockBadgeCurve1;
142 @Mock private RssiCurve mockBadgeCurve2;
143 @Mock private WifiManager mockWifiManager;
144 @Mock private WifiTracker.WifiListener mockWifiListener;
145
146 private final List<NetworkKey> mRequestedKeys = new ArrayList<>();
147
148 private Context mContext;
149 private CountDownLatch mAccessPointsChangedLatch;
150 private CountDownLatch mRequestScoresLatch;
151 private Handler mScannerHandler;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800152 private HandlerThread mWorkerThread;
Sundeep Ghuman42058742017-07-21 18:42:10 -0700153
Sundeep Ghumane869d832017-01-25 16:23:43 -0800154 private int mOriginalScoringUiSettingValue;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800155
156 @Before
157 public void setUp() {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800158 MockitoAnnotations.initMocks(this);
159
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800160 mContext = InstrumentationRegistry.getTargetContext();
161
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800162 mWorkerThread = new HandlerThread("TestHandlerWorkerThread");
163 mWorkerThread.start();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800164
165 // Make sure the scanner doesn't try to run on the testing thread.
166 HandlerThread scannerThread = new HandlerThread("ScannerWorkerThread");
167 scannerThread.start();
168 mScannerHandler = new Handler(scannerThread.getLooper());
169
170 when(mockWifiManager.isWifiEnabled()).thenReturn(true);
171 when(mockWifiManager.getScanResults())
172 .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2()));
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700173 when(mockWifiManager.getConfiguredNetworks())
174 .thenReturn(Arrays.asList(CONFIGURATION_1, CONFIGURATION_2));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800175
176
177 when(mockCurve1.lookupScore(RSSI_1)).thenReturn(SCORE_1);
178 when(mockCurve2.lookupScore(RSSI_2)).thenReturn(SCORE_2);
179
180 when(mockBadgeCurve1.lookupScore(RSSI_1)).thenReturn((byte) BADGE_1);
181 when(mockBadgeCurve2.lookupScore(RSSI_2)).thenReturn((byte) BADGE_2);
182
183 doNothing()
184 .when(mockNetworkScoreManager)
185 .registerNetworkScoreCache(
186 anyInt(),
187 mScoreCacheCaptor.capture(),
188 Matchers.anyInt());
189
190 // Capture requested keys and count down latch if present
191 doAnswer(
192 new Answer<Boolean>() {
193 @Override
194 public Boolean answer(InvocationOnMock input) {
195 if (mRequestScoresLatch != null) {
196 mRequestScoresLatch.countDown();
197 }
198 NetworkKey[] keys = (NetworkKey[]) input.getArguments()[0];
199 for (NetworkKey key : keys) {
200 mRequestedKeys.add(key);
201 }
202 return true;
203 }
204 }).when(mockNetworkScoreManager).requestScores(Matchers.<NetworkKey[]>any());
205
206 doAnswer(
207 new Answer<Void>() {
208 @Override
209 public Void answer (InvocationOnMock invocation) throws Throwable {
210 if (mAccessPointsChangedLatch != null) {
211 mAccessPointsChangedLatch.countDown();
212 }
213
214 return null;
215 }
216 }).when(mockWifiListener).onAccessPointsChanged();
217
Sundeep Ghumane869d832017-01-25 16:23:43 -0800218 // Turn on Scoring UI features
219 mOriginalScoringUiSettingValue = Settings.Global.getInt(
220 InstrumentationRegistry.getTargetContext().getContentResolver(),
221 Settings.Global.NETWORK_SCORING_UI_ENABLED,
222 0 /* disabled */);
223 Settings.Global.putInt(
224 InstrumentationRegistry.getTargetContext().getContentResolver(),
225 Settings.Global.NETWORK_SCORING_UI_ENABLED,
226 1 /* enabled */);
Sundeep Ghuman42058742017-07-21 18:42:10 -0700227
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800228 }
229
230 @After
231 public void cleanUp() {
232 Settings.Global.putInt(
Sundeep Ghumane869d832017-01-25 16:23:43 -0800233 InstrumentationRegistry.getTargetContext().getContentResolver(),
234 Settings.Global.NETWORK_SCORING_UI_ENABLED,
235 mOriginalScoringUiSettingValue);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800236 }
237
238 private static ScanResult buildScanResult1() {
239 return new ScanResult(
240 WifiSsid.createFromAsciiEncoded(SSID_1),
241 BSSID_1,
242 0, // hessid
243 0, //anqpDomainId
244 null, // osuProviders
245 "", // capabilities
246 RSSI_1,
247 0, // frequency
248 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
249 }
250
251 private static ScanResult buildScanResult2() {
252 return new ScanResult(
253 WifiSsid.createFromAsciiEncoded(SSID_2),
254 BSSID_2,
255 0, // hessid
256 0, //anqpDomainId
257 null, // osuProviders
258 "", // capabilities
259 RSSI_2,
260 0, // frequency
261 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
262 }
263
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800264 private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
265 Intent ... intents)
266 throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800267 WifiTracker tracker = createMockedWifiTracker();
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800268
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800269 startTracking(tracker);
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800270 for (Intent intent : intents) {
271 tracker.mReceiver.onReceive(mContext, intent);
272 }
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800273
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800274 sendScanResultsAndProcess(tracker);
Sundeep Ghumane8013092017-06-21 22:35:30 -0700275 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800276
277 return tracker;
278 }
279
280 private WifiTracker createMockedWifiTracker() {
Tony Mantler0edf09b2017-09-28 15:03:37 -0700281 final WifiTracker wifiTracker = new WifiTracker(
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -0700282 mContext,
283 mockWifiListener,
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -0700284 mockWifiManager,
285 mockConnectivityManager,
286 mockNetworkScoreManager,
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -0700287 new IntentFilter()); // empty filter to ignore system broadcasts
Tony Mantler0edf09b2017-09-28 15:03:37 -0700288 wifiTracker.setWorkThread(mWorkerThread);
289 return wifiTracker;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800290 }
291
292 private void startTracking(WifiTracker tracker) throws InterruptedException {
293 CountDownLatch latch = new CountDownLatch(1);
294 mScannerHandler.post(new Runnable() {
295 @Override
296 public void run() {
Tony Mantler0edf09b2017-09-28 15:03:37 -0700297 tracker.onStart();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800298 latch.countDown();
299 }
300 });
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800301 assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800302 }
303
304 private void sendScanResultsAndProcess(WifiTracker tracker) throws InterruptedException {
305 mAccessPointsChangedLatch = new CountDownLatch(1);
306 Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
307 tracker.mReceiver.onReceive(mContext, i);
308
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800309 assertTrue("Latch timed out",
310 mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800311 }
312
313 private void updateScores() {
314 Bundle attr1 = new Bundle();
315 attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve1);
316 ScoredNetwork sc1 =
317 new ScoredNetwork(
318 NETWORK_KEY_1,
319 mockCurve1,
320 false /* meteredHint */,
321 attr1);
322
323 Bundle attr2 = new Bundle();
324 attr2.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve2);
325 ScoredNetwork sc2 =
326 new ScoredNetwork(
327 NETWORK_KEY_2,
328 mockCurve2,
Stephen Chen21f68682017-04-04 13:23:31 -0700329 true /* meteredHint */,
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800330 attr2);
331
332 WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
333 scoreCache.updateScores(Arrays.asList(sc1, sc2));
334 }
335
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800336 private WifiTracker createTrackerWithScanResultsAndAccessPoint1Connected()
337 throws InterruptedException {
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700338 when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800339
340 WifiConfiguration configuration = new WifiConfiguration();
341 configuration.SSID = SSID_1;
342 configuration.BSSID = BSSID_1;
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700343 configuration.networkId = NETWORK_ID_1;
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800344
345 NetworkInfo networkInfo = new NetworkInfo(
346 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
347 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
348
349 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
350 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700351 WifiTracker tracker =
352 createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(intent);
353 assertThat(tracker.isConnected()).isTrue();
354 return tracker;
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800355 }
356
Sundeep Ghumane8013092017-06-21 22:35:30 -0700357 private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
358 throws InterruptedException {
Sundeep Ghumanc5bbecb2018-01-29 18:56:36 -0800359 // TODO(sghuman): This should no longer be necessary in a single work handler model
360
Sundeep Ghumane8013092017-06-21 22:35:30 -0700361 CountDownLatch workerLatch = new CountDownLatch(1);
362 tracker.mWorkHandler.post(() -> {
363 workerLatch.countDown();
364 });
365 assertTrue("Latch timed out while waiting for WorkerHandler",
366 workerLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghumane8013092017-06-21 22:35:30 -0700367 }
368
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700369 private void switchToNetwork2(WifiTracker tracker) throws InterruptedException {
370 NetworkInfo networkInfo = new NetworkInfo(
371 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
372 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "connecting", "test");
373
374 WifiInfo info = new WifiInfo();
375 info.setSSID(WifiSsid.createFromAsciiEncoded(SSID_2));
376 info.setBSSID(BSSID_2);
377 info.setRssi(CONNECTED_RSSI);
378 info.setNetworkId(NETWORK_ID_2);
379 when(mockWifiManager.getConnectionInfo()).thenReturn(info);
380
381 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
382 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
383 tracker.mReceiver.onReceive(mContext, intent);
384 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
385 }
386
Ajay Nadathur7d176bc2016-10-24 16:55:24 -0700387 @Test
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800388 public void startAndStopTrackingShouldRegisterAndUnregisterScoreCache()
389 throws InterruptedException {
390 WifiTracker tracker = createMockedWifiTracker();
391
392 // Test register
393 startTracking(tracker);
394 verify(mockNetworkScoreManager)
395 .registerNetworkScoreCache(
396 Matchers.anyInt(),
397 mScoreCacheCaptor.capture(),
398 Matchers.anyInt());
399
400 WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
401
Sundeep Ghumane869d832017-01-25 16:23:43 -0800402 CountDownLatch latch = new CountDownLatch(1);
403 doAnswer(
404 (invocation) -> {
405 latch.countDown();
406 return null;
407 }).when(mockNetworkScoreManager)
408 .unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
409
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800410 // Test unregister
Tony Mantler0edf09b2017-09-28 15:03:37 -0700411 tracker.onStop();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800412
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800413 assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800414 verify(mockNetworkScoreManager)
415 .unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
416 }
417
418 @Test
Amin Shaikha80ae0c2017-03-23 16:18:30 -0700419 public void testGetNumSavedNetworks() throws InterruptedException {
420 WifiConfiguration validConfig = new WifiConfiguration();
421 validConfig.SSID = SSID_1;
422 validConfig.BSSID = BSSID_1;
423
424 WifiConfiguration selfAddedNoAssociation = new WifiConfiguration();
Peter Qiuabea7262017-05-31 10:18:17 -0700425 selfAddedNoAssociation.ephemeral = true;
Amin Shaikha80ae0c2017-03-23 16:18:30 -0700426 selfAddedNoAssociation.selfAdded = true;
427 selfAddedNoAssociation.numAssociation = 0;
428 selfAddedNoAssociation.SSID = SSID_2;
429 selfAddedNoAssociation.BSSID = BSSID_2;
430
431 when(mockWifiManager.getConfiguredNetworks())
432 .thenReturn(Arrays.asList(validConfig, selfAddedNoAssociation));
433
434 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
435
436 assertEquals(1, tracker.getNumSavedNetworks());
437 }
438
439 @Test
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800440 public void startTrackingShouldSetConnectedAccessPointAsActive() throws InterruptedException {
Sundeep Ghumane8013092017-06-21 22:35:30 -0700441 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800442
443 List<AccessPoint> aps = tracker.getAccessPoints();
444
445 assertThat(aps).hasSize(2);
446 assertThat(aps.get(0).isActive()).isTrue();
447 }
448
449 @Test
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700450 public void startTrackingAfterStopTracking_shouldRequestNewScores()
451 throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800452 // Start the tracker and inject the initial scan results and then stop tracking
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800453 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800454
Tony Mantler0edf09b2017-09-28 15:03:37 -0700455 tracker.onStop();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800456 mRequestedKeys.clear();
457
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800458 mRequestScoresLatch = new CountDownLatch(1);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800459 startTracking(tracker);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700460 tracker.forceUpdate();
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800461 assertTrue("Latch timed out",
462 mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800463
464 assertTrue(mRequestedKeys.contains(NETWORK_KEY_1));
465 assertTrue(mRequestedKeys.contains(NETWORK_KEY_2));
466 }
467
468 @Test
Sundeep Ghuman75f94802017-06-26 16:05:40 -0700469 public void stopTracking_shouldNotClearExistingScores()
470 throws InterruptedException {
471 // Start the tracker and inject the initial scan results and then stop tracking
472 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
473 updateScoresAndWaitForAccessPointsChangedCallback(tracker);
Tony Mantler0edf09b2017-09-28 15:03:37 -0700474 tracker.onStop();
Sundeep Ghuman75f94802017-06-26 16:05:40 -0700475
476 assertThat(mScoreCacheCaptor.getValue().getScoredNetwork(NETWORK_KEY_1)).isNotNull();
477 }
478
479 @Test
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700480 public void scoreCacheUpdateScoresShouldTriggerOnAccessPointsChanged()
481 throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800482 WifiTracker tracker = createMockedWifiTracker();
483 startTracking(tracker);
484 sendScanResultsAndProcess(tracker);
485
Sundeep Ghumane8013092017-06-21 22:35:30 -0700486 updateScoresAndWaitForAccessPointsChangedCallback(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800487 }
488
Sundeep Ghumane8013092017-06-21 22:35:30 -0700489 private void updateScoresAndWaitForAccessPointsChangedCallback(WifiTracker tracker)
490 throws InterruptedException {
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800491 // Updating scores can happen together or one after the other, so the latch countdown is set
492 // to 2.
Sundeep Ghumane8013092017-06-21 22:35:30 -0700493 mAccessPointsChangedLatch = new CountDownLatch(1);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800494 updateScores();
Sundeep Ghumane8013092017-06-21 22:35:30 -0700495 assertTrue("onAccessPointChanged was not called after updating scores",
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700496 mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghumane8013092017-06-21 22:35:30 -0700497 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800498 }
499
500 @Test
501 public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700502 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800503 List<AccessPoint> aps = tracker.getAccessPoints();
504 assertTrue(aps.size() == 2);
505 assertEquals(aps.get(0).getSsidStr(), SSID_1);
506 assertEquals(aps.get(1).getSsidStr(), SSID_2);
507
Sundeep Ghumane8013092017-06-21 22:35:30 -0700508 updateScoresAndWaitForAccessPointsChangedCallback(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800509
510 aps = tracker.getAccessPoints();
511 assertTrue(aps.size() == 2);
512 assertEquals(aps.get(0).getSsidStr(), SSID_2);
513 assertEquals(aps.get(1).getSsidStr(), SSID_1);
Sundeep Ghumane869d832017-01-25 16:23:43 -0800514 }
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800515
Sundeep Ghumane869d832017-01-25 16:23:43 -0800516 @Test
517 public void scoreCacheUpdateScoresShouldNotChangeSortOrderWhenSortingDisabled()
518 throws InterruptedException {
519 Settings.Global.putInt(
520 InstrumentationRegistry.getTargetContext().getContentResolver(),
521 Settings.Global.NETWORK_SCORING_UI_ENABLED,
522 0 /* disabled */);
523
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800524 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumane869d832017-01-25 16:23:43 -0800525 List<AccessPoint> aps = tracker.getAccessPoints();
526 assertTrue(aps.size() == 2);
527 assertEquals(aps.get(0).getSsidStr(), SSID_1);
528 assertEquals(aps.get(1).getSsidStr(), SSID_2);
529
Sundeep Ghumane8013092017-06-21 22:35:30 -0700530 updateScoresAndWaitForAccessPointsChangedCallback(tracker);
Sundeep Ghumane869d832017-01-25 16:23:43 -0800531
532 aps = tracker.getAccessPoints();
533 assertTrue(aps.size() == 2);
534 assertEquals(aps.get(0).getSsidStr(), SSID_1);
535 assertEquals(aps.get(1).getSsidStr(), SSID_2);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800536 }
537
Sundeep Ghuman266b4092017-06-16 15:12:56 -0700538 @FlakyTest
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800539 @Test
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700540 public void scoreCacheUpdateScoresShouldInsertSpeedIntoAccessPoint()
541 throws InterruptedException {
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800542 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumane8013092017-06-21 22:35:30 -0700543 updateScoresAndWaitForAccessPointsChangedCallback(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800544
545 List<AccessPoint> aps = tracker.getAccessPoints();
546
547 for (AccessPoint ap : aps) {
548 if (ap.getSsidStr().equals(SSID_1)) {
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700549 assertEquals(BADGE_1, ap.getSpeed());
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800550 } else if (ap.getSsidStr().equals(SSID_2)) {
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700551 assertEquals(BADGE_2, ap.getSpeed());
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800552 }
553 }
554 }
555
556 @Test
Stephen Chen21f68682017-04-04 13:23:31 -0700557 public void scoreCacheUpdateMeteredShouldUpdateAccessPointMetering()
558 throws InterruptedException {
559 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumane8013092017-06-21 22:35:30 -0700560 updateScoresAndWaitForAccessPointsChangedCallback(tracker);
Stephen Chen21f68682017-04-04 13:23:31 -0700561
562 List<AccessPoint> aps = tracker.getAccessPoints();
563
564 for (AccessPoint ap : aps) {
565 if (ap.getSsidStr().equals(SSID_1)) {
566 assertFalse(ap.isMetered());
567 } else if (ap.getSsidStr().equals(SSID_2)) {
568 assertTrue(ap.isMetered());
569 }
570 }
571 }
572
573 @Test
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700574 public void noSpeedsShouldBeInsertedIntoAccessPointWhenScoringUiDisabled()
Sundeep Ghumane869d832017-01-25 16:23:43 -0800575 throws InterruptedException {
576 Settings.Global.putInt(
577 InstrumentationRegistry.getTargetContext().getContentResolver(),
578 Settings.Global.NETWORK_SCORING_UI_ENABLED,
579 0 /* disabled */);
580
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800581 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumane8013092017-06-21 22:35:30 -0700582 updateScoresAndWaitForAccessPointsChangedCallback(tracker);
Sundeep Ghumane869d832017-01-25 16:23:43 -0800583
584 List<AccessPoint> aps = tracker.getAccessPoints();
585
586 for (AccessPoint ap : aps) {
587 if (ap.getSsidStr().equals(SSID_1)) {
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700588 assertEquals(AccessPoint.Speed.NONE, ap.getSpeed());
Sundeep Ghumane869d832017-01-25 16:23:43 -0800589 } else if (ap.getSsidStr().equals(SSID_2)) {
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700590 assertEquals(AccessPoint.Speed.NONE, ap.getSpeed());
Sundeep Ghumane869d832017-01-25 16:23:43 -0800591 }
592 }
593 }
594
595 @Test
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800596 public void scoresShouldBeRequestedForNewScanResultOnly() throws InterruptedException {
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800597 // Scores can be requested together or serially depending on how the scan results are
598 // processed.
Sundeep Ghumanc5bbecb2018-01-29 18:56:36 -0800599 mRequestScoresLatch = new CountDownLatch(1);
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800600 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumanc5bbecb2018-01-29 18:56:36 -0800601 assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800602 mRequestedKeys.clear();
603
604 String ssid = "ssid3";
605 String bssid = "00:00:00:00:00:00";
606 ScanResult newResult = new ScanResult(
607 WifiSsid.createFromAsciiEncoded(ssid),
608 bssid,
609 0, // hessid
610 0, //anqpDomainId
611 null, // osuProviders
612 "", // capabilities
613 RSSI_1,
614 0, // frequency
615 SystemClock.elapsedRealtime() * 1000);
616 when(mockWifiManager.getScanResults())
617 .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2(), newResult));
618
619 mRequestScoresLatch = new CountDownLatch(1);
620 sendScanResultsAndProcess(tracker);
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800621 assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800622
623 assertEquals(1, mRequestedKeys.size());
624 assertTrue(mRequestedKeys.contains(new NetworkKey(new WifiKey('"' + ssid + '"', bssid))));
625 }
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800626
627 @Test
628 public void scoreCacheAndListenerShouldBeUnregisteredWhenStopTrackingIsCalled() throws Exception
629 {
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800630 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800631 WifiNetworkScoreCache cache = mScoreCacheCaptor.getValue();
632
Tony Mantler0edf09b2017-09-28 15:03:37 -0700633 tracker.onStop();
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800634 verify(mockNetworkScoreManager).unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, cache);
635
636 // Verify listener is unregistered so updating a score does not throw an error by posting
637 // a message to the dead work handler
638 mWorkerThread.quit();
639 updateScores();
640 }
Peter Qiuf5628382017-03-28 13:24:34 -0700641
642 /**
643 * Verify that tracking a Passpoint AP on a device with Passpoint disabled doesn't cause
644 * any crash.
645 *
646 * @throws Exception
647 */
648 @Test
649 public void trackPasspointApWithPasspointDisabled() throws Exception {
Sundeep Ghuman0d492e82018-01-26 12:45:02 -0800650 // TODO(sghuman): Delete this test and replace with a passpoint test
Peter Qiuf5628382017-03-28 13:24:34 -0700651 WifiTracker tracker = createMockedWifiTracker();
652
653 // Add a Passpoint AP to the scan results.
654 List<ScanResult> results = new ArrayList<>();
655 ScanResult passpointAp = new ScanResult(
656 WifiSsid.createFromAsciiEncoded(SSID_1),
657 BSSID_1,
658 0, // hessid
659 0, //anqpDomainId
660 null, // osuProviders
661 "", // capabilities
662 RSSI_1,
663 0, // frequency
664 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
665 passpointAp.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
666 results.add(passpointAp);
667
668 // Update access point and verify UnsupportedOperationException is being caught for
669 // call to WifiManager#getMatchingWifiConfig.
670 when(mockWifiManager.getConfiguredNetworks())
671 .thenReturn(new ArrayList<WifiConfiguration>());
672 when(mockWifiManager.getScanResults()).thenReturn(results);
Peter Qiuf5628382017-03-28 13:24:34 -0700673 tracker.forceUpdate();
Peter Qiuf5628382017-03-28 13:24:34 -0700674 }
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700675
676 @Test
677 public void rssiChangeBroadcastShouldUpdateConnectedAp() throws Exception {
678 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
679 assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
680
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700681 int newRssi = CONNECTED_RSSI + 10;
682 WifiInfo info = new WifiInfo(CONNECTED_AP_1_INFO);
683 info.setRssi(newRssi);
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700684
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700685 CountDownLatch latch = new CountDownLatch(1);
686
687 // Once the new info has been fetched, we need to wait for the access points to be copied
Michael Plass992588c2017-12-04 11:39:13 -0800688 mAccessPointsChangedLatch = new CountDownLatch(1);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700689 doAnswer(invocation -> {
690 latch.countDown();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700691 return info;
692 }).when(mockWifiManager).getConnectionInfo();
693
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700694 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.RSSI_CHANGED_ACTION));
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700695 assertTrue("New connection info never retrieved",
696 latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
697 assertTrue("onAccessPointsChanged never called",
698 mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700699
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700700 assertThat(tracker.getAccessPoints().get(0).getRssi()).isEqualTo(newRssi);
701 }
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700702
703 @Test
704 public void forceUpdateShouldSynchronouslyFetchLatestInformation() throws Exception {
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700705 Network mockNetwork = mock(Network.class);
706 when(mockWifiManager.getCurrentNetwork()).thenReturn(mockNetwork);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700707
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700708 when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
709
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700710 NetworkInfo networkInfo = new NetworkInfo(
711 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
712 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
713 when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(networkInfo);
714
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700715 WifiTracker tracker = createMockedWifiTracker();
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700716 tracker.forceUpdate();
717
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700718 verify(mockWifiManager).getConnectionInfo();
Sundeep Ghuman0d492e82018-01-26 12:45:02 -0800719 verify(mockWifiManager, times(1)).getConfiguredNetworks();
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700720 verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
721
Sundeep Ghumand2b84a82017-07-05 14:19:30 -0700722 verify(mockWifiListener, never()).onAccessPointsChanged(); // mStaleAccessPoints is true
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700723 assertThat(tracker.getAccessPoints().size()).isEqualTo(2);
724 assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
725 }
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700726
727 @Test
728 public void stopTrackingShouldRemoveWifiListenerCallbacks() throws Exception {
729 WifiTracker tracker = createMockedWifiTracker();
730 startTracking(tracker);
731
Michael Plassfd4a90d2017-12-04 14:01:51 -0800732 CountDownLatch ready = new CountDownLatch(1);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700733 CountDownLatch latch = new CountDownLatch(1);
734 CountDownLatch lock = new CountDownLatch(1);
Sundeep Ghuman91f4ccb2018-01-26 18:58:56 -0800735 tracker.mWorkHandler.post(() -> {
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700736 try {
Michael Plassfd4a90d2017-12-04 14:01:51 -0800737 ready.countDown();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700738 lock.await();
739 latch.countDown();
740 } catch (InterruptedException e) {
741 fail("Interrupted Exception while awaiting lock release: " + e);
742 }
743 });
744
745 // Enqueue messages
Sundeep Ghuman91f4ccb2018-01-26 18:58:56 -0800746 tracker.mWorkHandler.sendEmptyMessage(WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700747
Michael Plassfd4a90d2017-12-04 14:01:51 -0800748 try {
749 ready.await(); // Make sure we have entered the first message handler
750 } catch (InterruptedException e) {}
Tony Mantler0edf09b2017-09-28 15:03:37 -0700751 tracker.onStop();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700752
753 verify(mockWifiListener, atMost(1)).onAccessPointsChanged();
754 verify(mockWifiListener, atMost(1)).onConnectedChanged();
755 verify(mockWifiListener, atMost(1)).onWifiStateChanged(anyInt());
756
757 lock.countDown();
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700758 assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700759
Sundeep Ghuman91f4ccb2018-01-26 18:58:56 -0800760 assertThat(tracker.mWorkHandler.hasMessages(
761 WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS)).isFalse();
762 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700763
764 verifyNoMoreInteractions(mockWifiListener);
765 }
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700766
767 @Test
768 public void stopTrackingShouldSetStaleBitWhichPreventsCallbacksUntilNextScanResult()
769 throws Exception {
770 WifiTracker tracker = createMockedWifiTracker();
771 startTracking(tracker);
Sundeep Ghumane8013092017-06-21 22:35:30 -0700772 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700773
Tony Mantler0edf09b2017-09-28 15:03:37 -0700774 tracker.onStop();
Sundeep Ghumane8013092017-06-21 22:35:30 -0700775 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700776
777 startTracking(tracker);
778
779 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
780 tracker.mReceiver.onReceive(
781 mContext, new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION));
782 tracker.mReceiver.onReceive(
783 mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
784
Sundeep Ghumane8013092017-06-21 22:35:30 -0700785 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700786
787 verify(mockWifiListener, never()).onAccessPointsChanged();
788
789 sendScanResultsAndProcess(tracker); // verifies onAccessPointsChanged is invoked
790 }
Sundeep Ghumane8013092017-06-21 22:35:30 -0700791
792 @Test
Sundeep Ghumand2b84a82017-07-05 14:19:30 -0700793 public void startTrackingShouldNotSendAnyCallbacksUntilScanResultsAreProcessed()
794 throws Exception {
795 WifiTracker tracker = createMockedWifiTracker();
796 startTracking(tracker);
797 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
798
799 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
800 tracker.mReceiver.onReceive(
801 mContext, new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION));
802 tracker.mReceiver.onReceive(
803 mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
804
805 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
806 verify(mockWifiListener, never()).onAccessPointsChanged();
807
808 sendScanResultsAndProcess(tracker); // verifies onAccessPointsChanged is invoked
809 }
810
811 @Test
Sundeep Ghumane8013092017-06-21 22:35:30 -0700812 public void disablingWifiShouldClearExistingAccessPoints() throws Exception {
813 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
814
815 when(mockWifiManager.isWifiEnabled()).thenReturn(false);
816 mAccessPointsChangedLatch = new CountDownLatch(1);
817 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
818
Sundeep Ghumanc5bbecb2018-01-29 18:56:36 -0800819 assertTrue(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghumane8013092017-06-21 22:35:30 -0700820 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
821
822 assertThat(tracker.getAccessPoints()).isEmpty();
823 }
Sundeep Ghuman42058742017-07-21 18:42:10 -0700824
825 @Test
826 public void onConnectedChangedCallback_shouldNotBeInvokedWhenNoStateChange() throws Exception {
827 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
828 verify(mockWifiListener, times(1)).onConnectedChanged();
829
830 NetworkInfo networkInfo = new NetworkInfo(
831 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
832 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
833
834 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
835 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
836 tracker.mReceiver.onReceive(mContext, intent);
837
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700838 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghuman42058742017-07-21 18:42:10 -0700839 verify(mockWifiListener, times(1)).onConnectedChanged();
840 }
841
842 @Test
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700843 public void onConnectedChangedCallback_shouldBeInvokedWhenStateChanges() throws Exception {
Sundeep Ghuman42058742017-07-21 18:42:10 -0700844 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
845 verify(mockWifiListener, times(1)).onConnectedChanged();
846
847 NetworkInfo networkInfo = new NetworkInfo(
848 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
849 networkInfo.setDetailedState(
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700850 NetworkInfo.DetailedState.DISCONNECTED, "disconnected", "test");
Sundeep Ghuman42058742017-07-21 18:42:10 -0700851
852 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
853 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
854 tracker.mReceiver.onReceive(mContext, intent);
855
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700856 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
857 assertThat(tracker.isConnected()).isFalse();
Sundeep Ghuman42058742017-07-21 18:42:10 -0700858 verify(mockWifiListener, times(2)).onConnectedChanged();
859 }
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700860
861 @Test
862 public void updateNetworkInfoWithNewConnectedNetwork_switchesNetworks() throws Exception {
863 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
864
865 switchToNetwork2(tracker);
866
867 List<AccessPoint> aps = tracker.getAccessPoints();
868 assertThat(aps.get(0).getSsidStr()).isEqualTo(SSID_2);
869
870 assertThat(aps.get(0).isReachable()).isTrue();
871 assertThat(aps.get(1).isReachable()).isTrue();
872 }
Peter Qiuabea7262017-05-31 10:18:17 -0700873}