blob: edf414ddf32380444690a32cc457ee946a8ddb2a [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;
26import static org.mockito.Mockito.doAnswer;
27import static org.mockito.Mockito.doNothing;
Sundeep Ghumance6bab82017-04-19 16:21:46 -070028import static org.mockito.Mockito.mock;
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -070029import static org.mockito.Mockito.never;
Quang Luongda49e822019-01-15 14:48:25 -080030import static org.mockito.Mockito.spy;
Sundeep Ghumance6bab82017-04-19 16:21:46 -070031import static org.mockito.Mockito.times;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080032import static org.mockito.Mockito.verify;
33import static org.mockito.Mockito.when;
34
35import android.content.Context;
36import android.content.Intent;
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -070037import android.content.IntentFilter;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080038import android.net.ConnectivityManager;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070039import android.net.Network;
Sundeep Ghuman2b489902017-02-22 18:17:29 -080040import android.net.NetworkInfo;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080041import android.net.NetworkKey;
42import android.net.NetworkScoreManager;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080043import android.net.RssiCurve;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070044import android.net.ScoredNetwork;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080045import android.net.WifiKey;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070046import android.net.wifi.ScanResult;
47import android.net.wifi.WifiConfiguration;
Sundeep Ghuman2b489902017-02-22 18:17:29 -080048import android.net.wifi.WifiInfo;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080049import android.net.wifi.WifiManager;
50import android.net.wifi.WifiNetworkScoreCache;
51import android.net.wifi.WifiSsid;
Quang Luongda49e822019-01-15 14:48:25 -080052import android.net.wifi.hotspot2.OsuProvider;
53import android.net.wifi.hotspot2.PasspointConfiguration;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080054import android.os.Bundle;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080055import android.os.Handler;
56import android.os.HandlerThread;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070057import android.os.SystemClock;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080058import android.provider.Settings;
Quang Luongda49e822019-01-15 14:48:25 -080059import android.util.ArraySet;
60import android.util.Pair;
KOUSHIK PANUGANTI63bf06e2018-12-18 14:26:21 -080061
62import androidx.test.InstrumentationRegistry;
63import androidx.test.filters.SmallTest;
64import androidx.test.runner.AndroidJUnit4;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070065
Sundeep Ghuman93d591b2018-03-19 14:21:56 -070066import com.android.settingslib.utils.ThreadUtils;
67
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080068import org.junit.After;
69import org.junit.Before;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070070import org.junit.Test;
71import org.junit.runner.RunWith;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080072import org.mockito.ArgumentCaptor;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080073import org.mockito.Captor;
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -070074import org.mockito.Matchers;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080075import org.mockito.Mock;
76import org.mockito.MockitoAnnotations;
77import org.mockito.invocation.InvocationOnMock;
78import org.mockito.stubbing.Answer;
79
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070080import java.util.ArrayList;
81import java.util.Arrays;
Quang Luongda49e822019-01-15 14:48:25 -080082import java.util.HashMap;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070083import java.util.List;
Quang Luongda49e822019-01-15 14:48:25 -080084import java.util.Map;
85import java.util.Set;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080086import java.util.concurrent.CountDownLatch;
87import java.util.concurrent.TimeUnit;
Sundeep Ghumanbcb53732018-01-31 12:42:16 -080088import java.util.concurrent.atomic.AtomicBoolean;
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070089
Sundeep Ghuman2b489902017-02-22 18:17:29 -080090// TODO(sghuman): Change these to robolectric tests b/35766684.
Ajay Nadathur7d176bc2016-10-24 16:55:24 -070091@SmallTest
92@RunWith(AndroidJUnit4.class)
93public class WifiTrackerTest {
94
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080095 private static final String TAG = "WifiTrackerTest";
Sundeep Ghumanac7b4362017-02-08 17:19:27 -080096 private static final int LATCH_TIMEOUT = 4000;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -080097
98 private static final String SSID_1 = "ssid1";
99 private static final String BSSID_1 = "00:00:00:00:00:00";
100 private static final NetworkKey NETWORK_KEY_1 =
101 new NetworkKey(new WifiKey('"' + SSID_1 + '"', BSSID_1));
102 private static final int RSSI_1 = -30;
103 private static final byte SCORE_1 = 10;
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700104 private static final int BADGE_1 = AccessPoint.Speed.MODERATE;
Quang Luongda49e822019-01-15 14:48:25 -0800105 private static final String FQDN_1 = "fqdn1";
106 private static final String PROVIDER_FRIENDLY_NAME_1 = "providerFriendlyName1";
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800107
108 private static final String SSID_2 = "ssid2";
109 private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
110 private static final NetworkKey NETWORK_KEY_2 =
111 new NetworkKey(new WifiKey('"' + SSID_2 + '"', BSSID_2));
112 private static final int RSSI_2 = -30;
113 private static final byte SCORE_2 = 15;
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700114 private static final int BADGE_2 = AccessPoint.Speed.FAST;
Quang Luongda49e822019-01-15 14:48:25 -0800115 private static final String FQDN_2 = "fqdn2";
116 private static final String PROVIDER_FRIENDLY_NAME_2 = "providerFriendlyName2";
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800117
jackqdyulei396e52d2018-09-19 17:28:27 -0700118 private static final String SSID_3 = "ssid3";
119 private static final String BSSID_3 = "CC:00:00:00:00:00";
120 private static final int RSSI_3 = -40;
121
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700122 // TODO(b/65594609): Convert mutable Data objects to instance variables / builder pattern
123 private static final int NETWORK_ID_1 = 123;
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700124 private static final int CONNECTED_RSSI = -50;
125 private static final WifiInfo CONNECTED_AP_1_INFO = new WifiInfo();
126 static {
127 CONNECTED_AP_1_INFO.setSSID(WifiSsid.createFromAsciiEncoded(SSID_1));
128 CONNECTED_AP_1_INFO.setBSSID(BSSID_1);
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700129 CONNECTED_AP_1_INFO.setNetworkId(NETWORK_ID_1);
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700130 CONNECTED_AP_1_INFO.setRssi(CONNECTED_RSSI);
131 }
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700132 private static final WifiConfiguration CONFIGURATION_1 = new WifiConfiguration();
133 static {
134 CONFIGURATION_1.SSID = SSID_1;
135 CONFIGURATION_1.BSSID = BSSID_1;
136 CONFIGURATION_1.networkId = NETWORK_ID_1;
137 }
138
139 private static final int NETWORK_ID_2 = 2;
140 private static final WifiConfiguration CONFIGURATION_2 = new WifiConfiguration();
141 static {
142 CONFIGURATION_2.SSID = SSID_2;
143 CONFIGURATION_2.BSSID = BSSID_2;
144 CONFIGURATION_2.networkId = NETWORK_ID_2;
145 }
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700146
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800147 @Captor ArgumentCaptor<WifiNetworkScoreCache> mScoreCacheCaptor;
148 @Mock private ConnectivityManager mockConnectivityManager;
149 @Mock private NetworkScoreManager mockNetworkScoreManager;
150 @Mock private RssiCurve mockCurve1;
151 @Mock private RssiCurve mockCurve2;
152 @Mock private RssiCurve mockBadgeCurve1;
153 @Mock private RssiCurve mockBadgeCurve2;
154 @Mock private WifiManager mockWifiManager;
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700155 @Mock private WifiTracker.WifiListener mockWifiListener;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800156
157 private final List<NetworkKey> mRequestedKeys = new ArrayList<>();
158
159 private Context mContext;
160 private CountDownLatch mAccessPointsChangedLatch;
161 private CountDownLatch mRequestScoresLatch;
162 private Handler mScannerHandler;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800163 private HandlerThread mWorkerThread;
Sundeep Ghuman42058742017-07-21 18:42:10 -0700164
Sundeep Ghumane869d832017-01-25 16:23:43 -0800165 private int mOriginalScoringUiSettingValue;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800166
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800167 @SuppressWarnings("VisibleForTests")
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800168 @Before
169 public void setUp() {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800170 MockitoAnnotations.initMocks(this);
171
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800172 mContext = InstrumentationRegistry.getTargetContext();
173
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800174 mWorkerThread = new HandlerThread("TestHandlerWorkerThread");
175 mWorkerThread.start();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800176
177 // Make sure the scanner doesn't try to run on the testing thread.
178 HandlerThread scannerThread = new HandlerThread("ScannerWorkerThread");
179 scannerThread.start();
180 mScannerHandler = new Handler(scannerThread.getLooper());
181
182 when(mockWifiManager.isWifiEnabled()).thenReturn(true);
183 when(mockWifiManager.getScanResults())
184 .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2()));
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700185 when(mockWifiManager.getConfiguredNetworks())
186 .thenReturn(Arrays.asList(CONFIGURATION_1, CONFIGURATION_2));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800187
188
189 when(mockCurve1.lookupScore(RSSI_1)).thenReturn(SCORE_1);
190 when(mockCurve2.lookupScore(RSSI_2)).thenReturn(SCORE_2);
191
192 when(mockBadgeCurve1.lookupScore(RSSI_1)).thenReturn((byte) BADGE_1);
193 when(mockBadgeCurve2.lookupScore(RSSI_2)).thenReturn((byte) BADGE_2);
194
195 doNothing()
196 .when(mockNetworkScoreManager)
197 .registerNetworkScoreCache(
198 anyInt(),
199 mScoreCacheCaptor.capture(),
200 Matchers.anyInt());
201
202 // Capture requested keys and count down latch if present
203 doAnswer(
204 new Answer<Boolean>() {
205 @Override
206 public Boolean answer(InvocationOnMock input) {
207 if (mRequestScoresLatch != null) {
208 mRequestScoresLatch.countDown();
209 }
210 NetworkKey[] keys = (NetworkKey[]) input.getArguments()[0];
211 for (NetworkKey key : keys) {
212 mRequestedKeys.add(key);
213 }
214 return true;
215 }
216 }).when(mockNetworkScoreManager).requestScores(Matchers.<NetworkKey[]>any());
217
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800218 // We use a latch to detect callbacks as Tracker initialization state often invokes
219 // callbacks
220 doAnswer(invocation -> {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800221 if (mAccessPointsChangedLatch != null) {
222 mAccessPointsChangedLatch.countDown();
223 }
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800224 return null;
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700225 }).when(mockWifiListener).onAccessPointsChanged();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800226
Sundeep Ghumane869d832017-01-25 16:23:43 -0800227 // Turn on Scoring UI features
228 mOriginalScoringUiSettingValue = Settings.Global.getInt(
229 InstrumentationRegistry.getTargetContext().getContentResolver(),
230 Settings.Global.NETWORK_SCORING_UI_ENABLED,
231 0 /* disabled */);
232 Settings.Global.putInt(
233 InstrumentationRegistry.getTargetContext().getContentResolver(),
234 Settings.Global.NETWORK_SCORING_UI_ENABLED,
235 1 /* enabled */);
Sundeep Ghuman42058742017-07-21 18:42:10 -0700236
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800237 }
238
239 @After
240 public void cleanUp() {
241 Settings.Global.putInt(
Sundeep Ghumane869d832017-01-25 16:23:43 -0800242 InstrumentationRegistry.getTargetContext().getContentResolver(),
243 Settings.Global.NETWORK_SCORING_UI_ENABLED,
244 mOriginalScoringUiSettingValue);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800245 }
246
247 private static ScanResult buildScanResult1() {
248 return new ScanResult(
249 WifiSsid.createFromAsciiEncoded(SSID_1),
250 BSSID_1,
251 0, // hessid
252 0, //anqpDomainId
253 null, // osuProviders
254 "", // capabilities
255 RSSI_1,
256 0, // frequency
257 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
258 }
259
260 private static ScanResult buildScanResult2() {
261 return new ScanResult(
262 WifiSsid.createFromAsciiEncoded(SSID_2),
263 BSSID_2,
264 0, // hessid
265 0, //anqpDomainId
266 null, // osuProviders
267 "", // capabilities
268 RSSI_2,
269 0, // frequency
270 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
271 }
272
jackqdyulei396e52d2018-09-19 17:28:27 -0700273 private static ScanResult buildStaleScanResult() {
274 return new ScanResult(
275 WifiSsid.createFromAsciiEncoded(SSID_3),
276 BSSID_3,
277 0, // hessid
278 0, //anqpDomainId
279 null, // osuProviders
280 "", // capabilities
281 RSSI_3,
282 0, // frequency
283 0 /* microsecond timestamp */);
284 }
285
Quang Luongda49e822019-01-15 14:48:25 -0800286 private static WifiConfiguration buildPasspointConfiguration(String fqdn, String friendlyName) {
287 WifiConfiguration config = spy(new WifiConfiguration());
288 config.FQDN = fqdn;
289 config.providerFriendlyName = friendlyName;
290 when(config.isPasspoint()).thenReturn(true);
291 return config;
292 }
293
294 private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
295 createPasspointMatchingWifiConfigsWithDuplicates() {
296 List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
297 new ArrayList<>();
298 Map<Integer, List<ScanResult>> mapping = new HashMap<>();
299
300 mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Arrays.asList(buildScanResult1()));
301
302 WifiConfiguration passpointConfig1 =
303 buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1);
304 WifiConfiguration passpointConfig2 =
305 buildPasspointConfiguration(FQDN_2, PROVIDER_FRIENDLY_NAME_2);
306
307 matchingList.add(new Pair(passpointConfig1, mapping));
308 matchingList.add(new Pair(passpointConfig1, mapping));
309 matchingList.add(new Pair(passpointConfig2, mapping));
310 matchingList.add(new Pair(passpointConfig2, mapping));
311
312 return matchingList;
313 }
314
315 private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
316 createPasspointMatchingWifiConfigWithScanResults(
317 List<ScanResult> homeList, List<ScanResult> roamingList) {
318 List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
319 new ArrayList<>();
320 Map<Integer, List<ScanResult>> mapping = new HashMap<>();
321
322 if (homeList != null) {
323 mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, homeList);
324 }
325 if (roamingList != null) {
326 mapping.put(WifiManager.PASSPOINT_ROAMING_NETWORK, roamingList);
327 }
328
329 matchingList.add(new Pair(buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1),
330 mapping));
331
332 return matchingList;
333 }
334
335 private static OsuProvider buildOsuProvider(String friendlyName) {
336 Map<String, String> friendlyNames = new HashMap<>();
337 friendlyNames.put("en", friendlyName);
338 return new OsuProvider(null, friendlyNames, null, null, null, null, null);
339 }
340
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800341 private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
342 Intent ... intents)
343 throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800344 WifiTracker tracker = createMockedWifiTracker();
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800345
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800346 startTracking(tracker);
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800347 for (Intent intent : intents) {
348 tracker.mReceiver.onReceive(mContext, intent);
349 }
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800350
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800351 sendScanResults(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800352
353 return tracker;
354 }
355
356 private WifiTracker createMockedWifiTracker() {
Tony Mantler0edf09b2017-09-28 15:03:37 -0700357 final WifiTracker wifiTracker = new WifiTracker(
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -0700358 mContext,
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700359 mockWifiListener,
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -0700360 mockWifiManager,
361 mockConnectivityManager,
362 mockNetworkScoreManager,
Eric Schwarzenbach5e0535e2017-08-16 15:47:33 -0700363 new IntentFilter()); // empty filter to ignore system broadcasts
Tony Mantler0edf09b2017-09-28 15:03:37 -0700364 wifiTracker.setWorkThread(mWorkerThread);
365 return wifiTracker;
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800366 }
367
368 private void startTracking(WifiTracker tracker) throws InterruptedException {
369 CountDownLatch latch = new CountDownLatch(1);
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800370 mScannerHandler.post(() -> {
Tony Mantler0edf09b2017-09-28 15:03:37 -0700371 tracker.onStart();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800372 latch.countDown();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800373 });
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800374 assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800375 }
376
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800377 private void sendScanResults(WifiTracker tracker) throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800378 Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
379 tracker.mReceiver.onReceive(mContext, i);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800380 }
381
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800382 private void sendUpdatedScores() throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800383 Bundle attr1 = new Bundle();
384 attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve1);
385 ScoredNetwork sc1 =
386 new ScoredNetwork(
387 NETWORK_KEY_1,
388 mockCurve1,
389 false /* meteredHint */,
390 attr1);
391
392 Bundle attr2 = new Bundle();
393 attr2.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve2);
394 ScoredNetwork sc2 =
395 new ScoredNetwork(
396 NETWORK_KEY_2,
397 mockCurve2,
Stephen Chen21f68682017-04-04 13:23:31 -0700398 true /* meteredHint */,
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800399 attr2);
400
401 WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
402 scoreCache.updateScores(Arrays.asList(sc1, sc2));
403 }
404
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800405 private WifiTracker createTrackerWithScanResultsAndAccessPoint1Connected()
406 throws InterruptedException {
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700407 when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800408
409 WifiConfiguration configuration = new WifiConfiguration();
410 configuration.SSID = SSID_1;
411 configuration.BSSID = BSSID_1;
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700412 configuration.networkId = NETWORK_ID_1;
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800413
414 NetworkInfo networkInfo = new NetworkInfo(
415 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
416 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
417
418 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
419 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700420 WifiTracker tracker =
421 createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(intent);
422 assertThat(tracker.isConnected()).isTrue();
423 return tracker;
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800424 }
425
Sundeep Ghumane8013092017-06-21 22:35:30 -0700426 private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
427 throws InterruptedException {
428 CountDownLatch workerLatch = new CountDownLatch(1);
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800429 tracker.mWorkHandler.post(() -> workerLatch.countDown());
Sundeep Ghumane8013092017-06-21 22:35:30 -0700430 assertTrue("Latch timed out while waiting for WorkerHandler",
431 workerLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghumane8013092017-06-21 22:35:30 -0700432 }
433
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700434 private void switchToNetwork2(WifiTracker tracker) throws InterruptedException {
435 NetworkInfo networkInfo = new NetworkInfo(
436 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
437 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "connecting", "test");
438
439 WifiInfo info = new WifiInfo();
440 info.setSSID(WifiSsid.createFromAsciiEncoded(SSID_2));
441 info.setBSSID(BSSID_2);
442 info.setRssi(CONNECTED_RSSI);
443 info.setNetworkId(NETWORK_ID_2);
444 when(mockWifiManager.getConnectionInfo()).thenReturn(info);
445
446 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
447 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
448 tracker.mReceiver.onReceive(mContext, intent);
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700449 }
450
Ajay Nadathur7d176bc2016-10-24 16:55:24 -0700451 @Test
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800452 public void startAndStopTrackingShouldRegisterAndUnregisterScoreCache()
453 throws InterruptedException {
454 WifiTracker tracker = createMockedWifiTracker();
455
456 // Test register
457 startTracking(tracker);
458 verify(mockNetworkScoreManager)
459 .registerNetworkScoreCache(
460 Matchers.anyInt(),
461 mScoreCacheCaptor.capture(),
462 Matchers.anyInt());
463
464 WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
465
Sundeep Ghumane869d832017-01-25 16:23:43 -0800466 CountDownLatch latch = new CountDownLatch(1);
467 doAnswer(
468 (invocation) -> {
469 latch.countDown();
470 return null;
471 }).when(mockNetworkScoreManager)
472 .unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
473
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800474 // Test unregister
Tony Mantler0edf09b2017-09-28 15:03:37 -0700475 tracker.onStop();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800476
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800477 assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800478 verify(mockNetworkScoreManager)
479 .unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
480 }
481
482 @Test
Amin Shaikha80ae0c2017-03-23 16:18:30 -0700483 public void testGetNumSavedNetworks() throws InterruptedException {
484 WifiConfiguration validConfig = new WifiConfiguration();
485 validConfig.SSID = SSID_1;
486 validConfig.BSSID = BSSID_1;
487
488 WifiConfiguration selfAddedNoAssociation = new WifiConfiguration();
Peter Qiuabea7262017-05-31 10:18:17 -0700489 selfAddedNoAssociation.ephemeral = true;
Amin Shaikha80ae0c2017-03-23 16:18:30 -0700490 selfAddedNoAssociation.selfAdded = true;
491 selfAddedNoAssociation.numAssociation = 0;
492 selfAddedNoAssociation.SSID = SSID_2;
493 selfAddedNoAssociation.BSSID = BSSID_2;
494
495 when(mockWifiManager.getConfiguredNetworks())
496 .thenReturn(Arrays.asList(validConfig, selfAddedNoAssociation));
497
498 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
499
500 assertEquals(1, tracker.getNumSavedNetworks());
501 }
502
503 @Test
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800504 public void startTrackingShouldSetConnectedAccessPointAsActive() throws InterruptedException {
Sundeep Ghumane8013092017-06-21 22:35:30 -0700505 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800506
507 List<AccessPoint> aps = tracker.getAccessPoints();
508
509 assertThat(aps).hasSize(2);
510 assertThat(aps.get(0).isActive()).isTrue();
511 }
512
513 @Test
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700514 public void startTrackingAfterStopTracking_shouldRequestNewScores()
515 throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800516 // Start the tracker and inject the initial scan results and then stop tracking
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800517 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800518
Tony Mantler0edf09b2017-09-28 15:03:37 -0700519 tracker.onStop();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800520 mRequestedKeys.clear();
521
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800522 mRequestScoresLatch = new CountDownLatch(1);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800523 startTracking(tracker);
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800524 assertTrue("Latch timed out",
525 mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800526
527 assertTrue(mRequestedKeys.contains(NETWORK_KEY_1));
528 assertTrue(mRequestedKeys.contains(NETWORK_KEY_2));
529 }
530
531 @Test
Sundeep Ghuman75f94802017-06-26 16:05:40 -0700532 public void stopTracking_shouldNotClearExistingScores()
533 throws InterruptedException {
534 // Start the tracker and inject the initial scan results and then stop tracking
535 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800536 updateScoresAndWaitForCacheListenerToProcess(tracker);
Tony Mantler0edf09b2017-09-28 15:03:37 -0700537 tracker.onStop();
Sundeep Ghuman75f94802017-06-26 16:05:40 -0700538
539 assertThat(mScoreCacheCaptor.getValue().getScoredNetwork(NETWORK_KEY_1)).isNotNull();
540 }
541
542 @Test
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700543 public void scoreCacheUpdateScoresShouldTriggerOnAccessPointsChanged()
544 throws InterruptedException {
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800545 WifiTracker tracker = createMockedWifiTracker();
546 startTracking(tracker);
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800547 sendScanResults(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800548
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800549 updateScoresAndWaitForCacheListenerToProcess(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800550 }
551
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800552 private void updateScoresAndWaitForCacheListenerToProcess(WifiTracker tracker)
Sundeep Ghumane8013092017-06-21 22:35:30 -0700553 throws InterruptedException {
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800554 // Scores are updated via the cache listener hence we need to wait for the work handler
555 // to finish before proceeding.
556 sendUpdatedScores();
557
558 // Ensure the work handler has processed the scores inside the cache listener of WifiTracker
Sundeep Ghumane8013092017-06-21 22:35:30 -0700559 waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800560 }
561
562 @Test
563 public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700564 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800565 List<AccessPoint> aps = tracker.getAccessPoints();
566 assertTrue(aps.size() == 2);
567 assertEquals(aps.get(0).getSsidStr(), SSID_1);
568 assertEquals(aps.get(1).getSsidStr(), SSID_2);
569
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800570 updateScoresAndWaitForCacheListenerToProcess(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800571
572 aps = tracker.getAccessPoints();
573 assertTrue(aps.size() == 2);
574 assertEquals(aps.get(0).getSsidStr(), SSID_2);
575 assertEquals(aps.get(1).getSsidStr(), SSID_1);
Sundeep Ghumane869d832017-01-25 16:23:43 -0800576 }
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800577
Sundeep Ghumane869d832017-01-25 16:23:43 -0800578 @Test
579 public void scoreCacheUpdateScoresShouldNotChangeSortOrderWhenSortingDisabled()
580 throws InterruptedException {
581 Settings.Global.putInt(
582 InstrumentationRegistry.getTargetContext().getContentResolver(),
583 Settings.Global.NETWORK_SCORING_UI_ENABLED,
584 0 /* disabled */);
585
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800586 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumane869d832017-01-25 16:23:43 -0800587 List<AccessPoint> aps = tracker.getAccessPoints();
588 assertTrue(aps.size() == 2);
589 assertEquals(aps.get(0).getSsidStr(), SSID_1);
590 assertEquals(aps.get(1).getSsidStr(), SSID_2);
591
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800592 updateScoresAndWaitForCacheListenerToProcess(tracker);
Sundeep Ghumane869d832017-01-25 16:23:43 -0800593
594 aps = tracker.getAccessPoints();
595 assertTrue(aps.size() == 2);
596 assertEquals(aps.get(0).getSsidStr(), SSID_1);
597 assertEquals(aps.get(1).getSsidStr(), SSID_2);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800598 }
599
600 @Test
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700601 public void scoreCacheUpdateScoresShouldInsertSpeedIntoAccessPoint()
602 throws InterruptedException {
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800603 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800604 updateScoresAndWaitForCacheListenerToProcess(tracker);
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800605
606 List<AccessPoint> aps = tracker.getAccessPoints();
607
608 for (AccessPoint ap : aps) {
609 if (ap.getSsidStr().equals(SSID_1)) {
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700610 assertEquals(BADGE_1, ap.getSpeed());
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800611 } else if (ap.getSsidStr().equals(SSID_2)) {
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700612 assertEquals(BADGE_2, ap.getSpeed());
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800613 }
614 }
615 }
616
617 @Test
Stephen Chen21f68682017-04-04 13:23:31 -0700618 public void scoreCacheUpdateMeteredShouldUpdateAccessPointMetering()
619 throws InterruptedException {
620 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800621 updateScoresAndWaitForCacheListenerToProcess(tracker);
Stephen Chen21f68682017-04-04 13:23:31 -0700622
623 List<AccessPoint> aps = tracker.getAccessPoints();
624
625 for (AccessPoint ap : aps) {
626 if (ap.getSsidStr().equals(SSID_1)) {
627 assertFalse(ap.isMetered());
628 } else if (ap.getSsidStr().equals(SSID_2)) {
629 assertTrue(ap.isMetered());
630 }
631 }
632 }
633
634 @Test
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700635 public void noSpeedsShouldBeInsertedIntoAccessPointWhenScoringUiDisabled()
Sundeep Ghumane869d832017-01-25 16:23:43 -0800636 throws InterruptedException {
637 Settings.Global.putInt(
638 InstrumentationRegistry.getTargetContext().getContentResolver(),
639 Settings.Global.NETWORK_SCORING_UI_ENABLED,
640 0 /* disabled */);
641
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800642 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800643 updateScoresAndWaitForCacheListenerToProcess(tracker);
Sundeep Ghumane869d832017-01-25 16:23:43 -0800644
645 List<AccessPoint> aps = tracker.getAccessPoints();
646
647 for (AccessPoint ap : aps) {
648 if (ap.getSsidStr().equals(SSID_1)) {
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700649 assertEquals(AccessPoint.Speed.NONE, ap.getSpeed());
Sundeep Ghumane869d832017-01-25 16:23:43 -0800650 } else if (ap.getSsidStr().equals(SSID_2)) {
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700651 assertEquals(AccessPoint.Speed.NONE, ap.getSpeed());
Sundeep Ghumane869d832017-01-25 16:23:43 -0800652 }
653 }
654 }
655
656 @Test
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800657 public void scoresShouldBeRequestedForNewScanResultOnly() throws InterruptedException {
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800658 // Scores can be requested together or serially depending on how the scan results are
659 // processed.
Sundeep Ghumanc5bbecb2018-01-29 18:56:36 -0800660 mRequestScoresLatch = new CountDownLatch(1);
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800661 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumanc5bbecb2018-01-29 18:56:36 -0800662 assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800663 mRequestedKeys.clear();
664
665 String ssid = "ssid3";
666 String bssid = "00:00:00:00:00:00";
667 ScanResult newResult = new ScanResult(
668 WifiSsid.createFromAsciiEncoded(ssid),
669 bssid,
670 0, // hessid
671 0, //anqpDomainId
672 null, // osuProviders
673 "", // capabilities
674 RSSI_1,
675 0, // frequency
676 SystemClock.elapsedRealtime() * 1000);
677 when(mockWifiManager.getScanResults())
678 .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2(), newResult));
679
680 mRequestScoresLatch = new CountDownLatch(1);
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800681 sendScanResults(tracker);
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800682 assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman5519b7b2016-12-14 17:53:31 -0800683
684 assertEquals(1, mRequestedKeys.size());
685 assertTrue(mRequestedKeys.contains(new NetworkKey(new WifiKey('"' + ssid + '"', bssid))));
686 }
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800687
688 @Test
689 public void scoreCacheAndListenerShouldBeUnregisteredWhenStopTrackingIsCalled() throws Exception
690 {
Sundeep Ghuman2b489902017-02-22 18:17:29 -0800691 WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800692 WifiNetworkScoreCache cache = mScoreCacheCaptor.getValue();
693
Tony Mantler0edf09b2017-09-28 15:03:37 -0700694 tracker.onStop();
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800695 verify(mockNetworkScoreManager).unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, cache);
696
697 // Verify listener is unregistered so updating a score does not throw an error by posting
698 // a message to the dead work handler
699 mWorkerThread.quit();
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800700 sendUpdatedScores();
Sundeep Ghumanac7b4362017-02-08 17:19:27 -0800701 }
Peter Qiuf5628382017-03-28 13:24:34 -0700702
703 /**
704 * Verify that tracking a Passpoint AP on a device with Passpoint disabled doesn't cause
705 * any crash.
706 *
707 * @throws Exception
708 */
709 @Test
710 public void trackPasspointApWithPasspointDisabled() throws Exception {
Sundeep Ghuman0d492e82018-01-26 12:45:02 -0800711 // TODO(sghuman): Delete this test and replace with a passpoint test
Peter Qiuf5628382017-03-28 13:24:34 -0700712 WifiTracker tracker = createMockedWifiTracker();
713
714 // Add a Passpoint AP to the scan results.
715 List<ScanResult> results = new ArrayList<>();
716 ScanResult passpointAp = new ScanResult(
717 WifiSsid.createFromAsciiEncoded(SSID_1),
718 BSSID_1,
719 0, // hessid
720 0, //anqpDomainId
721 null, // osuProviders
722 "", // capabilities
723 RSSI_1,
724 0, // frequency
725 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
726 passpointAp.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
727 results.add(passpointAp);
728
729 // Update access point and verify UnsupportedOperationException is being caught for
730 // call to WifiManager#getMatchingWifiConfig.
731 when(mockWifiManager.getConfiguredNetworks())
732 .thenReturn(new ArrayList<WifiConfiguration>());
733 when(mockWifiManager.getScanResults()).thenReturn(results);
Sundeep Ghumanf3421742018-02-08 11:18:42 -0800734
735 startTracking(tracker);
Peter Qiuf5628382017-03-28 13:24:34 -0700736 }
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700737
738 @Test
739 public void rssiChangeBroadcastShouldUpdateConnectedAp() throws Exception {
740 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
741 assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
742
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700743 int newRssi = CONNECTED_RSSI + 10;
744 WifiInfo info = new WifiInfo(CONNECTED_AP_1_INFO);
745 info.setRssi(newRssi);
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700746
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700747 // 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 -0800748 mAccessPointsChangedLatch = new CountDownLatch(1);
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800749 doAnswer(invocation -> info).when(mockWifiManager).getConnectionInfo();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700750
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700751 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.RSSI_CHANGED_ACTION));
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800752
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700753 assertTrue("onAccessPointsChanged never called",
754 mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman8c792882017-04-04 17:23:29 -0700755 assertThat(tracker.getAccessPoints().get(0).getRssi()).isEqualTo(newRssi);
756 }
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700757
758 @Test
Sundeep Ghumanf3421742018-02-08 11:18:42 -0800759 public void onStartShouldSynchronouslyFetchLatestInformation() throws Exception {
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700760 Network mockNetwork = mock(Network.class);
761 when(mockWifiManager.getCurrentNetwork()).thenReturn(mockNetwork);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700762
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700763 when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
764
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700765 NetworkInfo networkInfo = new NetworkInfo(
766 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
767 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
768 when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(networkInfo);
769
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700770 WifiTracker tracker = createMockedWifiTracker();
Sundeep Ghumanf3421742018-02-08 11:18:42 -0800771 startTracking(tracker);
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700772
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700773 verify(mockWifiManager).getConnectionInfo();
Sundeep Ghuman0d492e82018-01-26 12:45:02 -0800774 verify(mockWifiManager, times(1)).getConfiguredNetworks();
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700775 verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
776
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800777 // mStaleAccessPoints is true
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700778 verify(mockWifiListener, never()).onAccessPointsChanged();
Sundeep Ghuman9c0b97e2017-04-13 16:05:46 -0700779 assertThat(tracker.getAccessPoints().size()).isEqualTo(2);
780 assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
781 }
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700782
783 @Test
Sundeep Ghuman06ec3be2018-02-20 19:51:15 -0800784 public void onStartShouldDisplayConnectedAccessPointWhenThereAreNoScanResults()
785 throws Exception {
786 Network mockNetwork = mock(Network.class);
787 when(mockWifiManager.getCurrentNetwork()).thenReturn(mockNetwork);
788
789 when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
790
791 NetworkInfo networkInfo = new NetworkInfo(
792 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
793 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
794 when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(networkInfo);
795
796 // Don't return any scan results
797 when(mockWifiManager.getScanResults()).thenReturn(new ArrayList<>());
798
799 WifiTracker tracker = createMockedWifiTracker();
800 startTracking(tracker);
801
802 verify(mockWifiManager).getConnectionInfo();
803 verify(mockWifiManager, times(1)).getConfiguredNetworks();
804 verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
805
806 // mStaleAccessPoints is true
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700807 verify(mockWifiListener, never()).onAccessPointsChanged();
Sundeep Ghuman06ec3be2018-02-20 19:51:15 -0800808
Sundeep Ghuman5fde6402018-02-21 20:51:39 -0800809 assertThat(tracker.getAccessPoints()).hasSize(1);
Sundeep Ghuman06ec3be2018-02-20 19:51:15 -0800810 assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
811 }
812
813 @Test
Sundeep Ghumanbcb53732018-01-31 12:42:16 -0800814 public void stopTrackingShouldRemoveAllPendingWork() throws Exception {
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700815 WifiTracker tracker = createMockedWifiTracker();
816 startTracking(tracker);
817
Michael Plassfd4a90d2017-12-04 14:01:51 -0800818 CountDownLatch ready = new CountDownLatch(1);
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700819 CountDownLatch latch = new CountDownLatch(1);
820 CountDownLatch lock = new CountDownLatch(1);
Sundeep Ghuman91f4ccb2018-01-26 18:58:56 -0800821 tracker.mWorkHandler.post(() -> {
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700822 try {
Michael Plassfd4a90d2017-12-04 14:01:51 -0800823 ready.countDown();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700824 lock.await();
825 latch.countDown();
826 } catch (InterruptedException e) {
827 fail("Interrupted Exception while awaiting lock release: " + e);
828 }
829 });
830
831 // Enqueue messages
Sundeep Ghumanbcb53732018-01-31 12:42:16 -0800832 final AtomicBoolean executed = new AtomicBoolean(false);
833 tracker.mWorkHandler.post(() -> executed.set(true));
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700834
Michael Plassfd4a90d2017-12-04 14:01:51 -0800835 try {
836 ready.await(); // Make sure we have entered the first message handler
837 } catch (InterruptedException e) {}
Tony Mantler0edf09b2017-09-28 15:03:37 -0700838 tracker.onStop();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700839
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700840 lock.countDown();
Sundeep Ghumance6bab82017-04-19 16:21:46 -0700841 assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700842
Sundeep Ghumanbcb53732018-01-31 12:42:16 -0800843 // In case the method was already executing
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800844 assertThat(tracker.mWorkHandler.hasMessagesOrCallbacks()).isFalse();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700845
Sundeep Ghumanbcb53732018-01-31 12:42:16 -0800846 assertThat(executed.get()).isFalse();
Sundeep Ghuman71f4a822017-04-18 19:51:46 -0700847 }
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700848
849 @Test
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700850 public void stopTrackingShouldPreventCallbacksFromOngoingWork() throws Exception {
851 WifiTracker tracker = createMockedWifiTracker();
852 startTracking(tracker);
853
854 final CountDownLatch ready = new CountDownLatch(1);
855 final CountDownLatch latch = new CountDownLatch(1);
856 final CountDownLatch lock = new CountDownLatch(1);
857 tracker.mWorkHandler.post(() -> {
858 try {
859 ready.countDown();
860 lock.await();
861
862 tracker.mReceiver.onReceive(
863 mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
864
865 latch.countDown();
866 } catch (InterruptedException e) {
867 fail("Interrupted Exception while awaiting lock release: " + e);
868 }
869 });
870
871 ready.await(); // Make sure we have entered the first message handler
872 tracker.onStop();
873 lock.countDown();
874 assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
875
876 // Wait for main thread
877 final CountDownLatch latch2 = new CountDownLatch(1);
878 ThreadUtils.postOnMainThread(latch2::countDown);
879 latch2.await();
880
881 verify(mockWifiListener, never()).onWifiStateChanged(anyInt());
882 }
883
884 @Test
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700885 public void stopTrackingShouldSetStaleBitWhichPreventsCallbacksUntilNextScanResult()
886 throws Exception {
887 WifiTracker tracker = createMockedWifiTracker();
888 startTracking(tracker);
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700889
Tony Mantler0edf09b2017-09-28 15:03:37 -0700890 tracker.onStop();
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700891
892 startTracking(tracker);
893
894 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
895 tracker.mReceiver.onReceive(
896 mContext, new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION));
897 tracker.mReceiver.onReceive(
898 mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
899
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700900
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700901 verify(mockWifiListener, never()).onAccessPointsChanged();
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700902
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800903 sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
Sundeep Ghumand4a79ac2017-06-07 18:11:39 -0700904 }
Sundeep Ghumane8013092017-06-21 22:35:30 -0700905
906 @Test
Sundeep Ghumand2b84a82017-07-05 14:19:30 -0700907 public void startTrackingShouldNotSendAnyCallbacksUntilScanResultsAreProcessed()
908 throws Exception {
909 WifiTracker tracker = createMockedWifiTracker();
910 startTracking(tracker);
Sundeep Ghumand2b84a82017-07-05 14:19:30 -0700911
912 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
913 tracker.mReceiver.onReceive(
914 mContext, new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION));
915 tracker.mReceiver.onReceive(
916 mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
917
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700918 verify(mockWifiListener, never()).onAccessPointsChanged();
Sundeep Ghumand2b84a82017-07-05 14:19:30 -0700919
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800920 sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
Sundeep Ghumand2b84a82017-07-05 14:19:30 -0700921 }
922
923 @Test
Sundeep Ghumane8013092017-06-21 22:35:30 -0700924 public void disablingWifiShouldClearExistingAccessPoints() throws Exception {
925 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
926
927 when(mockWifiManager.isWifiEnabled()).thenReturn(false);
Sundeep Ghumandc67f4d2018-01-31 16:03:33 -0800928
Sundeep Ghumane8013092017-06-21 22:35:30 -0700929 mAccessPointsChangedLatch = new CountDownLatch(1);
930 tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
Andreas Gampe7dbcb8f2018-02-26 11:36:41 -0800931 assertThat(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS)).isTrue();
Sundeep Ghumane8013092017-06-21 22:35:30 -0700932
933 assertThat(tracker.getAccessPoints()).isEmpty();
934 }
Sundeep Ghuman42058742017-07-21 18:42:10 -0700935
936 @Test
937 public void onConnectedChangedCallback_shouldNotBeInvokedWhenNoStateChange() throws Exception {
938 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700939 verify(mockWifiListener, times(1)).onConnectedChanged();
Sundeep Ghuman42058742017-07-21 18:42:10 -0700940
941 NetworkInfo networkInfo = new NetworkInfo(
942 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
943 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
944
945 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
946 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
947 tracker.mReceiver.onReceive(mContext, intent);
948
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700949 verify(mockWifiListener, times(1)).onConnectedChanged();
Sundeep Ghuman42058742017-07-21 18:42:10 -0700950 }
951
952 @Test
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700953 public void onConnectedChangedCallback_shouldBeInvokedWhenStateChanges() throws Exception {
Sundeep Ghuman42058742017-07-21 18:42:10 -0700954 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700955 verify(mockWifiListener, times(1)).onConnectedChanged();
Sundeep Ghuman42058742017-07-21 18:42:10 -0700956
957 NetworkInfo networkInfo = new NetworkInfo(
958 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
959 networkInfo.setDetailedState(
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700960 NetworkInfo.DetailedState.DISCONNECTED, "disconnected", "test");
Sundeep Ghuman42058742017-07-21 18:42:10 -0700961
962 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
963 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
964 tracker.mReceiver.onReceive(mContext, intent);
965
Sundeep Ghumandb2eabb2017-07-28 14:51:05 -0700966 assertThat(tracker.isConnected()).isFalse();
Sundeep Ghuman93d591b2018-03-19 14:21:56 -0700967 verify(mockWifiListener, times(2)).onConnectedChanged();
Sundeep Ghuman42058742017-07-21 18:42:10 -0700968 }
Sundeep Ghumandb9b94c2017-09-06 11:46:21 -0700969
970 @Test
971 public void updateNetworkInfoWithNewConnectedNetwork_switchesNetworks() throws Exception {
972 WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
973
974 switchToNetwork2(tracker);
975
976 List<AccessPoint> aps = tracker.getAccessPoints();
977 assertThat(aps.get(0).getSsidStr()).isEqualTo(SSID_2);
978
979 assertThat(aps.get(0).isReachable()).isTrue();
980 assertThat(aps.get(1).isReachable()).isTrue();
981 }
jackqdyulei396e52d2018-09-19 17:28:27 -0700982
983 @Test
984 public void onStart_updateScanResults_evictOldScanResult() {
985 when(mockWifiManager.getScanResults()).thenReturn(
986 Arrays.asList(buildScanResult1(), buildScanResult2(), buildStaleScanResult()));
987 WifiTracker tracker = createMockedWifiTracker();
988
989 tracker.forceUpdate();
990
991 // Only has scanResult1 and scanResult2
992 assertThat(tracker.getAccessPoints()).hasSize(2);
993 assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
994 assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
995 }
Quang Luongda49e822019-01-15 14:48:25 -0800996
997 /**
998 * Verifies that updatePasspointAccessPoints will only return AccessPoints whose
999 * isPasspoint() evaluates as true.
1000 */
1001 @Test
1002 public void updatePasspointAccessPoints_returnedAccessPointsArePasspoint() {
1003 WifiTracker tracker = createMockedWifiTracker();
1004
1005 List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
1006 createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());
1007
1008 assertTrue(passpointAccessPoints.size() != 0);
1009 for (AccessPoint ap : passpointAccessPoints) {
1010 assertTrue(ap.isPasspoint());
1011 }
1012 }
1013
1014 /**
1015 * Verifies that updatePasspointAccessPoints will return the same amount of AccessPoints as
1016 * unique WifiConfigurations, even if duplicate FQDNs exist.
1017 */
1018 @Test
1019 public void updatePasspointAccessPoints_ignoresDuplicateFQDNs() {
1020 WifiTracker tracker = createMockedWifiTracker();
1021
1022 // Process matching list of four configs with two duplicate FQDNs.
1023 List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
1024 createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());
1025
1026 // Should have 2 APs with unique FQDNs, ignoring the 2 duplicate FQDNs.
1027 assertThat(passpointAccessPoints).hasSize(2);
1028
1029 Set<String> fqdns = new ArraySet<>(Arrays.asList(FQDN_1, FQDN_2));
1030
1031 assertTrue(fqdns.remove(passpointAccessPoints.get(0).getConfig().FQDN));
1032 assertTrue(fqdns.remove(passpointAccessPoints.get(1).getConfig().FQDN));
1033 }
1034
1035 /**
1036 * Verifies that updatePasspointAccessPoints will return matching cached APs and update their
1037 * scan results instead of creating new APs.
1038 */
1039 @Test
1040 public void updatePasspointAccessPoints_usesCachedAccessPoints() {
1041 WifiTracker tracker = createMockedWifiTracker();
1042
1043 ScanResult result = buildScanResult1();
1044
1045 List<AccessPoint> passpointAccessPointsFirstUpdate = tracker.updatePasspointAccessPoints(
1046 createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
1047 null), new ArrayList<>());
1048 List<AccessPoint> cachedAccessPoints = new ArrayList<>(passpointAccessPointsFirstUpdate);
1049
1050 int prevRssi = result.level;
1051 int newRssi = prevRssi + 10;
1052 result.level = newRssi;
1053
1054 List<AccessPoint> passpointAccessPointsSecondUpdate = tracker.updatePasspointAccessPoints(
1055 createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
1056 null), cachedAccessPoints);
1057
1058 // Verify second update AP is the same object as the first update AP
1059 assertThat(passpointAccessPointsFirstUpdate.get(0))
1060 .isSameAs(passpointAccessPointsSecondUpdate.get(0));
1061 // Verify second update AP has the average of the first and second update RSSIs
1062 assertThat(passpointAccessPointsSecondUpdate.get(0).getRssi())
1063 .isEqualTo((prevRssi + newRssi) / 2);
1064 }
1065
1066 /**
1067 * Verifies that updateOsuAccessPoints will only return AccessPoints whose
1068 * isOsuProvider() evaluates as true.
1069 */
1070 @Test
1071 public void updateOsuAccessPoints_returnedAccessPointsAreOsuProviders() {
1072 WifiTracker tracker = createMockedWifiTracker();
1073
1074 Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
1075 providersAndScans.put(
1076 buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
1077 providersAndScans.put(
1078 buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));
1079
1080 List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
1081 providersAndScans, new ArrayList<>());
1082
1083 assertThat(osuAccessPoints).hasSize(2);
1084 for (AccessPoint ap: osuAccessPoints) {
1085 assertThat(ap.isOsuProvider()).isTrue();
1086 }
1087 }
1088
1089 /**
1090 * Verifies that updateOsuAccessPoints will not return Osu AccessPoints for already provisioned
1091 * networks
1092 */
1093 @Test
1094 public void updateOsuAccessPoints_doesNotReturnAlreadyProvisionedOsuAccessPoints() {
1095 WifiTracker tracker = createMockedWifiTracker();
1096
1097 // Start with two Osu Providers
1098 Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
1099 providersAndScans.put(
1100 buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
1101 providersAndScans.put(
1102 buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));
1103
1104 // First update
1105 List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
1106 providersAndScans, new ArrayList<>());
1107
1108 // Make sure both Osu Providers' APs are returned
1109 assertThat(osuAccessPoints).hasSize(2);
1110 List<String> friendlyNames = Arrays.asList(
1111 osuAccessPoints.get(0).getTitle(), osuAccessPoints.get(1).getTitle());
1112 assertThat(friendlyNames)
1113 .containsExactly(PROVIDER_FRIENDLY_NAME_1, PROVIDER_FRIENDLY_NAME_2);
1114
1115 // Simulate Osu Provider 1 being provisioned
1116 Map<OsuProvider, PasspointConfiguration> matchingPasspointConfigForOsuProvider =
1117 new HashMap<>();
1118 matchingPasspointConfigForOsuProvider.put(buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), null);
1119 when(mockWifiManager.getMatchingPasspointConfigsForOsuProviders(any())).thenReturn(
1120 matchingPasspointConfigForOsuProvider);
1121
1122 // Second update
1123 osuAccessPoints = tracker.updateOsuAccessPoints(
1124 providersAndScans, new ArrayList<>());
1125
1126 // Returned AP should only be for Osu Provider 2
1127 assertThat(osuAccessPoints).hasSize(1);
1128 assertThat(osuAccessPoints.get(0).getTitle()).isEqualTo(PROVIDER_FRIENDLY_NAME_2);
1129 }
1130
1131 /**
1132 * Verifies that updateOsuAccessPoints will return matching cached APs and update their
1133 * scan results instead of creating new APs.
1134 */
1135 @Test
1136 public void updateOsuAccessPoints_usesCachedAccessPoints() {
1137 WifiTracker tracker = createMockedWifiTracker();
1138
1139 ScanResult result = buildScanResult1();
1140
1141 Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
1142 providersAndScans.put(
1143 buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(result));
1144
1145 List<AccessPoint> osuAccessPointsFirstUpdate = tracker.updateOsuAccessPoints(
1146 providersAndScans, new ArrayList<>());
1147 List<AccessPoint> cachedAccessPoints = new ArrayList<>(osuAccessPointsFirstUpdate);
1148
1149 // New RSSI for second update
1150 int prevRssi = result.level;
1151 int newRssi = prevRssi + 10;
1152 result.level = newRssi;
1153
1154 List<AccessPoint> osuAccessPointsSecondUpdate = tracker.updateOsuAccessPoints(
1155 providersAndScans, cachedAccessPoints);
1156
1157 // Verify second update AP is the same object as the first update AP
Quang Luong8123f772019-02-08 16:30:12 -08001158 assertThat(osuAccessPointsFirstUpdate.get(0)).isSameAs(osuAccessPointsSecondUpdate.get(0));
Quang Luongda49e822019-01-15 14:48:25 -08001159 // Verify second update AP has the average of the first and second update RSSIs
1160 assertThat(osuAccessPointsSecondUpdate.get(0).getRssi())
1161 .isEqualTo((prevRssi + newRssi) / 2);
1162 }
Peter Qiuabea7262017-05-31 10:18:17 -07001163}