1 /*
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  */
16 package com.android.settingslib.wifi;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static com.google.common.truth.Truth.assertWithMessage;
20 
21 import static org.junit.Assert.fail;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.any;
24 import static org.mockito.Mockito.anyInt;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.spy;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.content.Context;
31 import android.content.ContextWrapper;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.PackageManager;
34 import android.content.res.Resources;
35 import android.net.ConnectivityManager;
36 import android.net.NetworkInfo;
37 import android.net.NetworkKey;
38 import android.net.RssiCurve;
39 import android.net.ScoredNetwork;
40 import android.net.WifiKey;
41 import android.net.wifi.ScanResult;
42 import android.net.wifi.WifiConfiguration;
43 import android.net.wifi.WifiConfiguration.KeyMgmt;
44 import android.net.wifi.WifiInfo;
45 import android.net.wifi.WifiManager;
46 import android.net.wifi.WifiNetworkScoreCache;
47 import android.net.wifi.WifiSsid;
48 import android.net.wifi.hotspot2.OsuProvider;
49 import android.net.wifi.hotspot2.PasspointConfiguration;
50 import android.net.wifi.hotspot2.ProvisioningCallback;
51 import android.net.wifi.hotspot2.pps.HomeSp;
52 import android.os.Bundle;
53 import android.os.Parcelable;
54 import android.os.SystemClock;
55 import android.text.SpannableString;
56 import android.text.format.DateUtils;
57 import android.util.ArraySet;
58 import android.util.Pair;
59 
60 import androidx.test.InstrumentationRegistry;
61 import androidx.test.filters.SmallTest;
62 import androidx.test.runner.AndroidJUnit4;
63 
64 import com.android.settingslib.R;
65 import com.android.settingslib.utils.ThreadUtils;
66 import com.android.settingslib.wifi.AccessPoint.Speed;
67 
68 import org.junit.Before;
69 import org.junit.Test;
70 import org.junit.runner.RunWith;
71 import org.mockito.Mock;
72 import org.mockito.MockitoAnnotations;
73 
74 import java.util.ArrayList;
75 import java.util.Arrays;
76 import java.util.Collections;
77 import java.util.HashMap;
78 import java.util.List;
79 import java.util.Map;
80 import java.util.Set;
81 import java.util.concurrent.CountDownLatch;
82 
83 @SmallTest
84 @RunWith(AndroidJUnit4.class)
85 public class AccessPointTest {
86     private static final String TEST_SSID = "\"test_ssid\"";
87     private static final String ROAMING_SSID = "\"roaming_ssid\"";
88     private static final String OSU_FRIENDLY_NAME = "osu_friendly_name";
89 
90     private ArrayList<ScanResult> mScanResults;
91     private ArrayList<ScanResult> mRoamingScans;
92 
93     private static final RssiCurve FAST_BADGE_CURVE =
94             new RssiCurve(-150, 10, new byte[]{Speed.FAST});
95     public static final String TEST_BSSID = "00:00:00:00:00:00";
96     private static final long MAX_SCORE_CACHE_AGE_MILLIS =
97             20 * DateUtils.MINUTE_IN_MILLIS;
98 
99     private Context mContext;
100     private int mMaxSignalLevel;
101     private WifiInfo mWifiInfo;
102     @Mock private Context mMockContext;
103     @Mock private WifiManager mMockWifiManager;
104     @Mock private RssiCurve mockBadgeCurve;
105     @Mock private WifiNetworkScoreCache mockWifiNetworkScoreCache;
106     @Mock private AccessPoint.AccessPointListener mMockAccessPointListener;
107     @Mock private WifiManager.ActionListener mMockConnectListener;
108     private static final int NETWORK_ID = 123;
109     private static final int DEFAULT_RSSI = -55;
110 
createScanResult(String ssid, String bssid, int rssi)111     private ScanResult createScanResult(String ssid, String bssid, int rssi) {
112         ScanResult scanResult = new ScanResult();
113         scanResult.SSID = ssid;
114         scanResult.level = rssi;
115         scanResult.BSSID = bssid;
116         scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
117         scanResult.capabilities = "";
118         return scanResult;
119     }
120 
createOsuProvider()121     private OsuProvider createOsuProvider() {
122         Map<String, String> friendlyNames = new HashMap<>();
123         friendlyNames.put("en", OSU_FRIENDLY_NAME);
124         return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null);
125     }
126 
127     @Before
setUp()128     public void setUp() {
129         MockitoAnnotations.initMocks(this);
130         mContext = InstrumentationRegistry.getTargetContext();
131         mMaxSignalLevel = mContext.getSystemService(WifiManager.class).getMaxSignalLevel();
132         mWifiInfo = new WifiInfo();
133         mWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
134         mWifiInfo.setBSSID(TEST_BSSID);
135         mScanResults = buildScanResultCache(TEST_SSID);
136         mRoamingScans = buildScanResultCache(ROAMING_SSID);
137         WifiTracker.sVerboseLogging = false;
138     }
139 
140     @Test
testSsidIsSpannableString_returnFalse()141     public void testSsidIsSpannableString_returnFalse() {
142         final Bundle bundle = new Bundle();
143         bundle.putString("key_ssid", TEST_SSID);
144         final AccessPoint ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
145         final CharSequence ssid = ap.getSsid();
146 
147         assertThat(ssid instanceof SpannableString).isFalse();
148     }
149 
150     @Test
testCompareTo_GivesNull()151     public void testCompareTo_GivesNull() {
152         WifiConfiguration spyConfig = spy(new WifiConfiguration());
153 
154         when(spyConfig.isPasspoint()).thenReturn(true);
155         spyConfig.providerFriendlyName = null;
156         AccessPoint passpointAp = new AccessPoint(mContext, spyConfig);
157 
158         assertThat(passpointAp.getTitle()).isEqualTo("");
159     }
160 
161     @Test
testCompareTo_GivesActiveBeforeInactive()162     public void testCompareTo_GivesActiveBeforeInactive() {
163         AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
164         AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
165 
166         assertSortingWorks(activeAp, inactiveAp);
167     }
168 
169     @Test
testCompareTo_GivesReachableBeforeUnreachable()170     public void testCompareTo_GivesReachableBeforeUnreachable() {
171         AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
172         AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
173 
174         assertSortingWorks(nearAp, farAp);
175     }
176 
177     @Test
testCompareTo_GivesSavedBeforeUnsaved()178     public void testCompareTo_GivesSavedBeforeUnsaved() {
179         AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
180         AccessPoint notSavedAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
181 
182         assertSortingWorks(savedAp, notSavedAp);
183     }
184 
185     @Test
testCompareTo_GivesHighSpeedBeforeLowSpeed()186     public void testCompareTo_GivesHighSpeedBeforeLowSpeed() {
187         AccessPoint fastAp = new TestAccessPointBuilder(mContext).setSpeed(Speed.FAST).build();
188         AccessPoint slowAp = new TestAccessPointBuilder(mContext).setSpeed(Speed.SLOW).build();
189 
190         assertSortingWorks(fastAp, slowAp);
191     }
192 
193     @Test
testCompareTo_GivesHighLevelBeforeLowLevel()194     public void testCompareTo_GivesHighLevelBeforeLowLevel() {
195         final int highLevel = mMaxSignalLevel;
196         final int lowLevel = 1;
197         assertThat(highLevel).isGreaterThan(lowLevel);
198 
199         AccessPoint strongAp = new TestAccessPointBuilder(mContext).setLevel(highLevel).build();
200         AccessPoint weakAp = new TestAccessPointBuilder(mContext).setLevel(lowLevel).build();
201 
202         assertSortingWorks(strongAp, weakAp);
203     }
204 
205     @Test
testCompareTo_GivesSsidAlphabetically()206     public void testCompareTo_GivesSsidAlphabetically() {
207 
208         final String firstName = "AAAAAA";
209         final String secondName = "zzzzzz";
210 
211         AccessPoint firstAp = new TestAccessPointBuilder(mContext).setSsid(firstName).build();
212         AccessPoint secondAp = new TestAccessPointBuilder(mContext).setSsid(secondName).build();
213 
214         assertThat(firstAp.getSsidStr().compareToIgnoreCase(secondAp.getSsidStr()) < 0).isTrue();
215         assertSortingWorks(firstAp, secondAp);
216     }
217 
218     @Test
219     public void testCompareTo_GivesSsidCasePrecendenceAfterAlphabetical() {
220 
221         final String firstName = "aaAaaa";
222         final String secondName = "aaaaaa";
223         final String thirdName = "BBBBBB";
224 
225         AccessPoint firstAp = new TestAccessPointBuilder(mContext).setSsid(firstName).build();
226         AccessPoint secondAp = new TestAccessPointBuilder(mContext).setSsid(secondName).build();
227         AccessPoint thirdAp = new TestAccessPointBuilder(mContext).setSsid(thirdName).build();
228 
229         assertSortingWorks(firstAp, secondAp);
230         assertSortingWorks(secondAp, thirdAp);
231     }
232 
233     @Test
234     public void testCompareTo_AllSortingRulesCombined() {
235 
236         AccessPoint active = new TestAccessPointBuilder(mContext).setActive(true).build();
237         AccessPoint reachableAndMinLevel = new TestAccessPointBuilder(mContext)
238                 .setReachable(true).build();
239         AccessPoint saved = new TestAccessPointBuilder(mContext).setSaved(true).build();
240         AccessPoint highLevelAndReachable = new TestAccessPointBuilder(mContext)
241                 .setLevel(mMaxSignalLevel).build();
242         AccessPoint firstName = new TestAccessPointBuilder(mContext).setSsid("a").build();
243         AccessPoint lastname = new TestAccessPointBuilder(mContext).setSsid("z").build();
244 
245         ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
246         points.add(lastname);
247         points.add(firstName);
248         points.add(highLevelAndReachable);
249         points.add(saved);
250         points.add(reachableAndMinLevel);
251         points.add(active);
252 
253         Collections.sort(points);
254         assertThat(points.indexOf(active)).isLessThan(points.indexOf(reachableAndMinLevel));
255         assertThat(points.indexOf(reachableAndMinLevel)).isLessThan(points.indexOf(saved));
256         // note: the saved AP will not appear before highLevelAndReachable,
257         // because all APs with a signal level are reachable,
258         // and isReachable() takes higher sorting precedence than isSaved().
259         assertThat(points.indexOf(saved)).isLessThan(points.indexOf(firstName));
260         assertThat(points.indexOf(highLevelAndReachable)).isLessThan(points.indexOf(firstName));
261         assertThat(points.indexOf(firstName)).isLessThan(points.indexOf(lastname));
262     }
263 
264     @Test
265     public void testRssiIsSetFromScanResults() {
266         AccessPoint ap = createAccessPointWithScanResultCache();
267         int originalRssi = ap.getRssi();
268         assertThat(originalRssi).isNotEqualTo(AccessPoint.UNREACHABLE_RSSI);
269     }
270 
271     @Test
272     public void testGetRssiShouldReturnSetRssiValue() {
273         AccessPoint ap = createAccessPointWithScanResultCache();
274         int originalRssi = ap.getRssi();
275         int newRssi = originalRssi - 10;
276         ap.setRssi(newRssi);
277         assertThat(ap.getRssi()).isEqualTo(newRssi);
278     }
279 
280     @Test
281     public void testUpdateWithScanResultShouldAverageRssi() {
282         String ssid = "ssid";
283         int originalRssi = -65;
284         int newRssi = -80;
285         int expectedRssi = (originalRssi + newRssi) / 2;
286         AccessPoint ap =
287                 new TestAccessPointBuilder(mContext).setSsid(ssid).setRssi(originalRssi).build();
288 
289         ScanResult scanResult = new ScanResult();
290         scanResult.SSID = ssid;
291         scanResult.level = newRssi;
292         scanResult.BSSID = "bssid";
293         scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
294         scanResult.capabilities = "";
295 
296         ap.setScanResults(Collections.singletonList(scanResult));
297 
298         assertThat(ap.getRssi()).isEqualTo(expectedRssi);
299     }
300 
301     @Test
302     public void testCreateFromPasspointConfig() {
303         PasspointConfiguration config = new PasspointConfiguration();
304         HomeSp homeSp = new HomeSp();
305         homeSp.setFqdn("test.com");
306         homeSp.setFriendlyName("Test Provider");
307         config.setHomeSp(homeSp);
308         AccessPoint ap = new AccessPoint(mContext, config);
309         assertThat(ap.isPasspointConfig()).isTrue();
310     }
311 
312     @Test
313     public void testIsMetered_returnTrueWhenWifiConfigurationIsMetered() {
314         WifiConfiguration configuration = createWifiConfiguration();
315         configuration.meteredHint = true;
316 
317         NetworkInfo networkInfo =
318                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
319         AccessPoint accessPoint = new AccessPoint(mContext, configuration);
320         WifiInfo wifiInfo = new WifiInfo();
321         wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
322         wifiInfo.setBSSID(configuration.BSSID);
323         wifiInfo.setNetworkId(configuration.networkId);
324         accessPoint.update(configuration, wifiInfo, networkInfo);
325 
326         assertThat(accessPoint.isMetered()).isTrue();
327     }
328 
329     @Test
330     public void testIsMetered_returnTrueWhenWifiInfoIsMetered() {
331         WifiConfiguration configuration = createWifiConfiguration();
332 
333         NetworkInfo networkInfo =
334                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
335         AccessPoint accessPoint = new AccessPoint(mContext, configuration);
336         WifiInfo wifiInfo = new WifiInfo();
337         wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
338         wifiInfo.setBSSID(configuration.BSSID);
339         wifiInfo.setNetworkId(configuration.networkId);
340         wifiInfo.setMeteredHint(true);
341         accessPoint.update(configuration, wifiInfo, networkInfo);
342 
343         assertThat(accessPoint.isMetered()).isTrue();
344     }
345 
346     @Test
347     public void testIsMetered_returnTrueWhenScoredNetworkIsMetered() {
348         AccessPoint ap = createAccessPointWithScanResultCache();
349 
350         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
351                 .thenReturn(
352                         new ScoredNetwork(
353                                 null /* NetworkKey */,
354                                 null /* rssiCurve */,
355                                 true /* metered */));
356         ap.update(mockWifiNetworkScoreCache, false /* scoringUiEnabled */,
357                 MAX_SCORE_CACHE_AGE_MILLIS);
358 
359         assertThat(ap.isMetered()).isTrue();
360     }
361 
362     @Test
363     public void testIsMetered_returnFalseByDefault() {
364         WifiConfiguration configuration = createWifiConfiguration();
365 
366         NetworkInfo networkInfo =
367                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
368         AccessPoint accessPoint = new AccessPoint(mContext, configuration);
369         WifiInfo wifiInfo = new WifiInfo();
370         wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
371         wifiInfo.setBSSID(configuration.BSSID);
372         wifiInfo.setNetworkId(configuration.networkId);
373         accessPoint.update(configuration, wifiInfo, networkInfo);
374 
375         assertThat(accessPoint.isMetered()).isFalse();
376     }
377 
378     @Test
379     public void testSpeedLabel_returnsVeryFast() {
380         AccessPoint ap = createAccessPointWithScanResultCache();
381 
382         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
383                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
384         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
385 
386         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
387                 MAX_SCORE_CACHE_AGE_MILLIS);
388 
389         assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.VERY_FAST);
390         assertThat(ap.getSpeedLabel())
391                 .isEqualTo(mContext.getString(R.string.speed_label_very_fast));
392     }
393 
394     @Test
395     public void testSpeedLabel_returnsFast() {
396         AccessPoint ap = createAccessPointWithScanResultCache();
397 
398         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
399                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
400         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.FAST);
401 
402         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
403                 MAX_SCORE_CACHE_AGE_MILLIS);
404 
405         assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.FAST);
406         assertThat(ap.getSpeedLabel())
407                 .isEqualTo(mContext.getString(R.string.speed_label_fast));
408     }
409 
410     @Test
411     public void testSpeedLabel_returnsOkay() {
412         AccessPoint ap = createAccessPointWithScanResultCache();
413 
414         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
415                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
416         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.MODERATE);
417 
418         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
419                 MAX_SCORE_CACHE_AGE_MILLIS);
420 
421         assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.MODERATE);
422         assertThat(ap.getSpeedLabel())
423                 .isEqualTo(mContext.getString(R.string.speed_label_okay));
424     }
425 
426     @Test
427     public void testSpeedLabel_returnsSlow() {
428         AccessPoint ap = createAccessPointWithScanResultCache();
429 
430         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
431                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
432         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.SLOW);
433 
434         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
435                 MAX_SCORE_CACHE_AGE_MILLIS);
436 
437         assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.SLOW);
438         assertThat(ap.getSpeedLabel())
439                 .isEqualTo(mContext.getString(R.string.speed_label_slow));
440     }
441 
442     @Test
443     public void testSummaryString_showsSpeedLabel() {
444         AccessPoint ap = createAccessPointWithScanResultCache();
445 
446         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
447                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
448         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
449 
450         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
451                 MAX_SCORE_CACHE_AGE_MILLIS);
452 
453         assertThat(ap.getSummary()).isEqualTo(mContext.getString(R.string.speed_label_very_fast));
454     }
455 
456     @Test
457     public void testSummaryString_concatenatesSpeedLabel() {
458         AccessPoint ap = createAccessPointWithScanResultCache();
459         ap.update(new WifiConfiguration());
460 
461         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
462                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
463         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
464 
465         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
466                 MAX_SCORE_CACHE_AGE_MILLIS);
467 
468         String expectedString = mContext.getString(R.string.speed_label_very_fast) + " / "
469                 + mContext.getString(R.string.wifi_remembered);
470         assertThat(ap.getSummary()).isEqualTo(expectedString);
471     }
472 
473     @Test
474     public void testSummaryString_showsWrongPasswordLabel() {
475         WifiConfiguration configuration = spy(createWifiConfiguration());
476         WifiConfiguration.NetworkSelectionStatus status =
477                 mock(WifiConfiguration.NetworkSelectionStatus.class);
478         when(configuration.getNetworkSelectionStatus()).thenReturn(status);
479         when(status.getNetworkSelectionStatus()).thenReturn(
480                 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED);
481         when(status.getNetworkSelectionDisableReason()).thenReturn(
482                 WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
483         AccessPoint ap = new AccessPoint(mContext, configuration);
484 
485         assertThat(ap.getSummary()).isEqualTo(mContext.getString(
486                 R.string.wifi_check_password_try_again));
487     }
488 
489     @Test
490     public void testSummaryString_showsDisconnected() {
491         AccessPoint ap = createAccessPointWithScanResultCache();
492         ap.update(new WifiConfiguration());
493 
494         assertThat(ap.getSettingsSummary(true /*convertSavedAsDisconnected*/))
495                 .isEqualTo(mContext.getString(R.string.wifi_disconnected));
496     }
497 
498     @Test
499     public void testSummaryString_concatenatedMeteredAndDisconnected() {
500         AccessPoint ap = createAccessPointWithScanResultCache();
501         WifiConfiguration config = new WifiConfiguration();
502         config.meteredHint = true;
503         ap.update(config);
504 
505         String expectedString =
506                 mContext.getResources().getString(R.string.preference_summary_default_combination,
507                         mContext.getString(R.string.wifi_metered_label),
508                         mContext.getString(R.string.wifi_disconnected));
509         assertThat(ap.getSettingsSummary(true /*convertSavedAsDisconnected*/))
510                 .isEqualTo(expectedString);
511     }
512 
513     @Test
514     public void testSummaryString_showsConnectedViaSuggestionOrSpecifierApp() throws Exception {
515         final int rssi = -55;
516         final String appPackageName = "com.test.app";
517         final CharSequence appLabel = "Test App";
518         final String connectedViaAppResourceString = "Connected via ";
519 
520         WifiInfo wifiInfo = new WifiInfo();
521         wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
522         wifiInfo.setEphemeral(true);
523         wifiInfo.setRequestingPackageName(appPackageName);
524         wifiInfo.setRssi(rssi);
525 
526         Context context = mock(Context.class);
527         Resources resources = mock(Resources.class);
528         PackageManager packageManager = mock(PackageManager.class);
529         ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
530         when(context.getPackageManager()).thenReturn(packageManager);
531         when(context.getResources()).thenReturn(resources);
532         when(resources.getString(R.string.connected_via_app, appLabel))
533                 .thenReturn(connectedViaAppResourceString + appLabel.toString());
534         when(packageManager.getApplicationInfoAsUser(eq(appPackageName), anyInt(), anyInt()))
535                 .thenReturn(applicationInfo);
536         when(applicationInfo.loadLabel(packageManager)).thenReturn(appLabel);
537         when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
538         when(mMockWifiManager.calculateSignalLevel(rssi)).thenReturn(4);
539 
540         NetworkInfo networkInfo =
541                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
542         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
543 
544         AccessPoint ap = new TestAccessPointBuilder(context)
545                 .setSsid(TEST_SSID)
546                 .setNetworkInfo(networkInfo)
547                 .setRssi(rssi)
548                 .setSecurity(AccessPoint.SECURITY_NONE)
549                 .setWifiInfo(wifiInfo)
550                 .build();
551         assertThat(ap.getSummary()).isEqualTo("Connected via Test App");
552     }
553 
554     private ScoredNetwork buildScoredNetworkWithMockBadgeCurve() {
555         return buildScoredNetworkWithGivenBadgeCurve(mockBadgeCurve);
556     }
557 
558     private ScoredNetwork buildScoredNetworkWithGivenBadgeCurve(RssiCurve badgeCurve) {
559         Bundle attr1 = new Bundle();
560         attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, badgeCurve);
561         return new ScoredNetwork(
562                 new NetworkKey(new WifiKey(TEST_SSID, TEST_BSSID)),
563                 badgeCurve,
564                 false /* meteredHint */,
565                 attr1);
566     }
567 
568     private AccessPoint createAccessPointWithScanResultCache() {
569         Bundle bundle = new Bundle();
570         bundle.putParcelableArray(
571                 AccessPoint.KEY_SCANRESULTS,
572                 mScanResults.toArray(new Parcelable[mScanResults.size()]));
573         return new AccessPoint(mContext, bundle);
574     }
575 
576     private ArrayList<ScanResult> buildScanResultCache(String ssid) {
577         ArrayList<ScanResult> scanResults = new ArrayList<>();
578         for (int i = 0; i < 5; i++) {
579             ScanResult scanResult = createScanResult(ssid, "bssid-" + i, i);
580             scanResults.add(scanResult);
581         }
582         return scanResults;
583     }
584 
585     private WifiConfiguration createWifiConfiguration() {
586         WifiConfiguration configuration = new WifiConfiguration();
587         configuration.BSSID = "bssid";
588         configuration.SSID = "ssid";
589         configuration.networkId = 123;
590         return configuration;
591     }
592 
593     private AccessPoint createApWithFastTimestampedScoredNetworkCache(
594             long elapsedTimeMillis) {
595         TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork(
596                 buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE),
597                 elapsedTimeMillis);
598         return new TestAccessPointBuilder(mContext)
599                 .setSsid(TEST_SSID)
600                 .setScoredNetworkCache(
601                         new ArrayList<>(Arrays.asList(recentScore)))
602                 .build();
603     }
604 
605     /**
606     * Assert that the first AccessPoint appears before the second AccessPoint
607     * once sorting has been completed.
608     */
609     private void assertSortingWorks(AccessPoint first, AccessPoint second) {
610 
611         ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
612 
613         // add in reverse order so we can tell that sorting actually changed something
614         points.add(second);
615         points.add(first);
616         Collections.sort(points);
617         assertWithMessage(
618                 String.format("After sorting: second AccessPoint should have higher array index "
619                     + "than the first, but found indicies second '%s' and first '%s'.",
620                     points.indexOf(second), points.indexOf(first)))
621             .that(points.indexOf(second)).isGreaterThan(points.indexOf(first));
622     }
623 
624     @Test
625     public void testBuilder_setActive() {
626         AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
627         assertThat(activeAp.isActive()).isTrue();
628 
629         AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
630         assertThat(inactiveAp.isActive()).isFalse();
631     }
632 
633     @Test
634     public void testBuilder_setReachable() {
635         AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
636         assertThat(nearAp.isReachable()).isTrue();
637 
638         AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
639         assertThat(farAp.isReachable()).isFalse();
640     }
641 
642     @Test
643     public void testBuilder_setSaved() {
644         AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
645         assertThat(savedAp.isSaved()).isTrue();
646 
647         AccessPoint newAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
648         assertThat(newAp.isSaved()).isFalse();
649     }
650 
651     @Test
652     public void testBuilder_setLevel() {
653         AccessPoint testAp;
654 
655         for (int i = 0; i <= mMaxSignalLevel; i++) {
656             testAp = new TestAccessPointBuilder(mContext).setLevel(i).build();
657             assertThat(testAp.getLevel()).isEqualTo(i);
658         }
659 
660         // numbers larger than the max level should be set to max
661         testAp = new TestAccessPointBuilder(mContext).setLevel(mMaxSignalLevel + 1).build();
662         assertThat(testAp.getLevel()).isEqualTo(mMaxSignalLevel);
663 
664         // numbers less than 0 should give level 0
665         testAp = new TestAccessPointBuilder(mContext).setLevel(-100).build();
666         assertThat(testAp.getLevel()).isEqualTo(0);
667     }
668 
669     @Test
670     public void testBuilder_settingReachableAfterLevelDoesNotAffectLevel() {
671         int level = 1;
672         assertThat(level).isLessThan(mMaxSignalLevel);
673 
674         AccessPoint testAp =
675                 new TestAccessPointBuilder(mContext).setLevel(level).setReachable(true).build();
676         assertThat(testAp.getLevel()).isEqualTo(level);
677     }
678 
679     @Test
680     public void testBuilder_setSsid() {
681         String name = "AmazingSsid!";
682         AccessPoint namedAp = new TestAccessPointBuilder(mContext).setSsid(name).build();
683         assertThat(namedAp.getSsidStr()).isEqualTo(name);
684     }
685 
686     @Test
687     public void testBuilder_passpointConfig() {
688         String fqdn = "Test.com";
689         String providerFriendlyName = "Test Provider";
690         AccessPoint ap = new TestAccessPointBuilder(mContext).setFqdn(fqdn)
691                 .setProviderFriendlyName(providerFriendlyName).build();
692         assertThat(ap.isPasspointConfig()).isTrue();
693         assertThat(ap.getPasspointFqdn()).isEqualTo(fqdn);
694         assertThat(ap.getTitle()).isEqualTo(providerFriendlyName);
695     }
696 
697     // This method doesn't copy mIsFailover, mIsAvailable and mIsRoaming because NetworkInfo
698     // doesn't expose those three set methods. But that's fine since the tests don't use those three
699     // variables.
700     private NetworkInfo copyNetworkInfo(NetworkInfo ni) {
701         final NetworkInfo copy = new NetworkInfo(ni.getType(), ni.getSubtype(), ni.getTypeName(),
702                 ni.getSubtypeName());
703         copy.setDetailedState(ni.getDetailedState(), ni.getReason(), ni.getExtraInfo());
704         return copy;
705     }
706 
707     @Test
708     public void testUpdateNetworkInfo_returnsTrue() {
709         int networkId = 123;
710         int rssi = -55;
711         WifiConfiguration config = new WifiConfiguration();
712         config.networkId = networkId;
713         WifiInfo wifiInfo = new WifiInfo();
714         wifiInfo.setNetworkId(networkId);
715         wifiInfo.setRssi(rssi);
716 
717         NetworkInfo networkInfo =
718                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
719         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
720 
721         AccessPoint ap = new TestAccessPointBuilder(mContext)
722                 .setNetworkInfo(networkInfo)
723                 .setNetworkId(networkId)
724                 .setRssi(rssi)
725                 .setWifiInfo(wifiInfo)
726                 .build();
727 
728         NetworkInfo newInfo = copyNetworkInfo(networkInfo);
729         newInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
730         assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
731     }
732 
733     @Test
734     public void testUpdateNetworkInfoWithSameInfo_returnsFalse() {
735         int networkId = 123;
736         int rssi = -55;
737         WifiConfiguration config = new WifiConfiguration();
738         config.networkId = networkId;
739         WifiInfo wifiInfo = new WifiInfo();
740         wifiInfo.setNetworkId(networkId);
741         wifiInfo.setRssi(rssi);
742 
743         NetworkInfo networkInfo =
744                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
745         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
746 
747         AccessPoint ap = new TestAccessPointBuilder(mContext)
748                 .setNetworkInfo(networkInfo)
749                 .setNetworkId(networkId)
750                 .setRssi(rssi)
751                 .setWifiInfo(wifiInfo)
752                 .build();
753 
754         NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
755         assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
756     }
757 
758     @Test
759     public void testUpdateWithDifferentRssi_returnsTrue() {
760         int networkId = 123;
761         int rssi = -55;
762         WifiConfiguration config = new WifiConfiguration();
763         config.networkId = networkId;
764         WifiInfo wifiInfo = new WifiInfo();
765         wifiInfo.setNetworkId(networkId);
766         wifiInfo.setRssi(rssi);
767 
768         NetworkInfo networkInfo =
769                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
770         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
771 
772         AccessPoint ap = new TestAccessPointBuilder(mContext)
773                 .setNetworkInfo(networkInfo)
774                 .setNetworkId(networkId)
775                 .setRssi(rssi)
776                 .setWifiInfo(wifiInfo)
777                 .build();
778 
779         NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
780         wifiInfo.setRssi(rssi + 1);
781         assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
782     }
783 
784     @Test
785     public void testUpdateWithInvalidRssi_returnsFalse() {
786         int networkId = 123;
787         int rssi = -55;
788         WifiConfiguration config = new WifiConfiguration();
789         config.networkId = networkId;
790         WifiInfo wifiInfo = new WifiInfo();
791         wifiInfo.setNetworkId(networkId);
792         wifiInfo.setRssi(rssi);
793 
794         NetworkInfo networkInfo =
795                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
796         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
797 
798         AccessPoint ap = new TestAccessPointBuilder(mContext)
799                 .setNetworkInfo(networkInfo)
800                 .setNetworkId(networkId)
801                 .setRssi(rssi)
802                 .setWifiInfo(wifiInfo)
803                 .build();
804 
805         NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
806         wifiInfo.setRssi(WifiInfo.INVALID_RSSI);
807         assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
808     }
809     @Test
810     public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener()
811             throws InterruptedException {
812         WifiConfiguration config = new WifiConfiguration();
813         config.networkId = NETWORK_ID;
814         config.numNoInternetAccessReports = 1;
815 
816         WifiInfo wifiInfo = new WifiInfo();
817         wifiInfo.setNetworkId(NETWORK_ID);
818         wifiInfo.setRssi(DEFAULT_RSSI);
819 
820         NetworkInfo networkInfo =
821                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
822         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
823 
824         AccessPoint ap = new TestAccessPointBuilder(mContext)
825                 .setNetworkInfo(networkInfo)
826                 .setNetworkId(NETWORK_ID)
827                 .setRssi(DEFAULT_RSSI)
828                 .setWifiInfo(wifiInfo)
829                 .build();
830 
831         AccessPoint.AccessPointListener mockListener = mock(AccessPoint.AccessPointListener.class);
832         ap.setListener(mockListener);
833         WifiConfiguration newConfig = new WifiConfiguration(config);
834         config.validatedInternetAccess = true;
835 
836         assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse();
837 
838         // Wait for MainHandler to process callback
839         CountDownLatch latch = new CountDownLatch(1);
840         ThreadUtils.postOnMainThread(latch::countDown);
841 
842         latch.await();
843         verify(mockListener).onAccessPointChanged(ap);
844     }
845 
846     @Test
847     public void testConnectionInfo_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution()
848             throws InterruptedException {
849         WifiConfiguration config = new WifiConfiguration();
850         config.networkId = NETWORK_ID;
851         config.numNoInternetAccessReports = 1;
852 
853         WifiInfo wifiInfo = new WifiInfo();
854         wifiInfo.setNetworkId(NETWORK_ID);
855         wifiInfo.setRssi(DEFAULT_RSSI);
856 
857         NetworkInfo networkInfo =
858                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
859         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
860 
861         AccessPoint ap = new TestAccessPointBuilder(mContext)
862                 .setNetworkInfo(networkInfo)
863                 .setNetworkId(NETWORK_ID)
864                 .setRssi(DEFAULT_RSSI)
865                 .setWifiInfo(wifiInfo)
866                 .build();
867 
868         WifiConfiguration newConfig = new WifiConfiguration(config);
869         config.validatedInternetAccess = true;
870 
871         performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
872                 ap, () -> assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse());
873 
874     }
875 
876     private void performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
877             AccessPoint ap, Runnable r) {
878         AccessPoint.AccessPointListener mockListener = mock(AccessPoint.AccessPointListener.class);
879         ap.setListener(mockListener);
880 
881         // Put a latch on the MainHandler to prevent the callback from being invoked instantly
882         CountDownLatch latch1 = new CountDownLatch(1);
883         ThreadUtils.postOnMainThread(() -> {
884             try{
885                 latch1.await();
886             } catch (InterruptedException e) {
887                 fail("Interruped Exception thrown while awaiting latch countdown");
888             }
889         });
890 
891         r.run();
892 
893         ap.setListener(null);
894         latch1.countDown();
895 
896         // The second latch ensures the previously posted listener invocation has processed on the
897         // main thread.
898         CountDownLatch latch2 = new CountDownLatch(1);
899         ThreadUtils.postOnMainThread(latch2::countDown);
900 
901         try{
902             latch2.await();
903         } catch (InterruptedException e) {
904             fail("Interruped Exception thrown while awaiting latch countdown");
905         }
906     }
907 
908     @Test
909     public void testUpdateScanResults_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution()
910             throws InterruptedException {
911         String ssid = "ssid";
912         int newRssi = -80;
913         AccessPoint ap = new TestAccessPointBuilder(mContext).setSsid(ssid).build();
914 
915         ScanResult scanResult = new ScanResult();
916         scanResult.SSID = ssid;
917         scanResult.level = newRssi;
918         scanResult.BSSID = "bssid";
919         scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
920         scanResult.capabilities = "";
921 
922         performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
923                 ap, () -> ap.setScanResults(Collections.singletonList(scanResult)));
924     }
925 
926     @Test
testUpdateConfig_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution()927     public void testUpdateConfig_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution()
928             throws InterruptedException {
929         WifiConfiguration config = new WifiConfiguration();
930         config.networkId = NETWORK_ID;
931         config.numNoInternetAccessReports = 1;
932 
933         WifiInfo wifiInfo = new WifiInfo();
934         wifiInfo.setNetworkId(NETWORK_ID);
935         wifiInfo.setRssi(DEFAULT_RSSI);
936 
937         NetworkInfo networkInfo =
938                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
939         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
940 
941         AccessPoint ap = new TestAccessPointBuilder(mContext)
942                 .setNetworkInfo(networkInfo)
943                 .setNetworkId(NETWORK_ID)
944                 .setRssi(DEFAULT_RSSI)
945                 .setWifiInfo(wifiInfo)
946                 .build();
947 
948         WifiConfiguration newConfig = new WifiConfiguration(config);
949         config.validatedInternetAccess = true;
950 
951         performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
952                 ap, () -> ap.update(newConfig));
953     }
954 
955     @Test
testUpdateWithNullWifiConfiguration_doesNotThrowNPE()956     public void testUpdateWithNullWifiConfiguration_doesNotThrowNPE() {
957         WifiConfiguration config = new WifiConfiguration();
958         config.networkId = NETWORK_ID;
959         WifiInfo wifiInfo = new WifiInfo();
960         wifiInfo.setNetworkId(NETWORK_ID);
961         wifiInfo.setRssi(DEFAULT_RSSI);
962 
963         NetworkInfo networkInfo =
964                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
965         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
966 
967         AccessPoint ap = new TestAccessPointBuilder(mContext)
968                 .setNetworkInfo(networkInfo)
969                 .setNetworkId(NETWORK_ID)
970                 .setRssi(DEFAULT_RSSI)
971                 .setWifiInfo(wifiInfo)
972                 .build();
973 
974         ap.update(null, wifiInfo, networkInfo);
975     }
976 
977     @Test
testSpeedLabelAveragesAllBssidScores()978     public void testSpeedLabelAveragesAllBssidScores() {
979         AccessPoint ap = createAccessPointWithScanResultCache();
980 
981         int speed1 = Speed.MODERATE;
982         RssiCurve badgeCurve1 = mock(RssiCurve.class);
983         when(badgeCurve1.lookupScore(anyInt())).thenReturn((byte) speed1);
984         when(mockWifiNetworkScoreCache.getScoredNetwork(mScanResults.get(0)))
985                 .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve1));
986         int speed2 = Speed.VERY_FAST;
987         RssiCurve badgeCurve2 = mock(RssiCurve.class);
988         when(badgeCurve2.lookupScore(anyInt())).thenReturn((byte) speed2);
989         when(mockWifiNetworkScoreCache.getScoredNetwork(mScanResults.get(1)))
990                 .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2));
991 
992         int expectedSpeed = (speed1 + speed2) / 2;
993 
994         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
995                 MAX_SCORE_CACHE_AGE_MILLIS);
996 
997         assertThat(ap.getSpeed()).isEqualTo(expectedSpeed);
998     }
999 
1000     @Test
testSpeedLabelAverageIgnoresNoSpeedScores()1001     public void testSpeedLabelAverageIgnoresNoSpeedScores() {
1002         AccessPoint ap = createAccessPointWithScanResultCache();
1003 
1004         int speed1 = Speed.VERY_FAST;
1005         RssiCurve badgeCurve1 = mock(RssiCurve.class);
1006         when(badgeCurve1.lookupScore(anyInt())).thenReturn((byte) speed1);
1007         when(mockWifiNetworkScoreCache.getScoredNetwork(mScanResults.get(0)))
1008                 .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve1));
1009         int speed2 = Speed.NONE;
1010         RssiCurve badgeCurve2 = mock(RssiCurve.class);
1011         when(badgeCurve2.lookupScore(anyInt())).thenReturn((byte) speed2);
1012         when(mockWifiNetworkScoreCache.getScoredNetwork(mScanResults.get(1)))
1013                 .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2));
1014 
1015         ap.update(
1016             mockWifiNetworkScoreCache, true /* scoringUiEnabled */, MAX_SCORE_CACHE_AGE_MILLIS);
1017 
1018         assertThat(ap.getSpeed()).isEqualTo(speed1);
1019     }
1020 
1021     @Test
testSpeedLabelFallbackScoreIgnoresNullCurves()1022     public void testSpeedLabelFallbackScoreIgnoresNullCurves() {
1023         String bssid = "00:00:00:00:00:00";
1024 
1025         WifiInfo info = new WifiInfo();
1026         info.setRssi(DEFAULT_RSSI);
1027         info.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
1028         info.setBSSID(bssid);
1029         info.setNetworkId(NETWORK_ID);
1030 
1031         ArrayList<ScanResult> scanResults = new ArrayList<>();
1032         ScanResult scanResultUnconnected =
1033                 createScanResult(TEST_SSID, "11:11:11:11:11:11", DEFAULT_RSSI);
1034         scanResults.add(scanResultUnconnected);
1035 
1036         ScanResult scanResultConnected =
1037                 createScanResult(TEST_SSID, bssid, DEFAULT_RSSI);
1038         scanResults.add(scanResultConnected);
1039 
1040         AccessPoint ap =
1041                 new TestAccessPointBuilder(mContext)
1042                         .setActive(true)
1043                         .setNetworkId(NETWORK_ID)
1044                         .setSsid(TEST_SSID)
1045                         .setScanResults(scanResults)
1046                         .setWifiInfo(info)
1047                         .build();
1048 
1049         int fallbackSpeed = Speed.SLOW;
1050         when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultUnconnected))
1051                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
1052         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) fallbackSpeed);
1053 
1054         when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultConnected))
1055                 .thenReturn(null);
1056 
1057         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1058                 MAX_SCORE_CACHE_AGE_MILLIS);
1059 
1060         assertThat(ap.getSpeed()).isEqualTo(fallbackSpeed);
1061     }
1062 
1063     @Test
testScoredNetworkCacheBundling()1064     public void testScoredNetworkCacheBundling() {
1065         long timeMillis = SystemClock.elapsedRealtime();
1066         AccessPoint ap = createApWithFastTimestampedScoredNetworkCache(timeMillis);
1067         Bundle bundle = new Bundle();
1068         ap.saveWifiState(bundle);
1069 
1070         ArrayList<TimestampedScoredNetwork> list =
1071                 bundle.getParcelableArrayList(AccessPoint.KEY_SCOREDNETWORKCACHE);
1072         assertThat(list).hasSize(1);
1073         assertThat(list.get(0).getUpdatedTimestampMillis()).isEqualTo(timeMillis);
1074 
1075         RssiCurve curve = list.get(0).getScore().attributes.getParcelable(
1076                 ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE);
1077         assertThat(curve).isEqualTo(FAST_BADGE_CURVE);
1078     }
1079 
1080     @Test
testRecentNetworkScoresAreUsedForSpeedLabelGeneration()1081     public void testRecentNetworkScoresAreUsedForSpeedLabelGeneration() {
1082         AccessPoint ap =
1083                 createApWithFastTimestampedScoredNetworkCache(SystemClock.elapsedRealtime());
1084 
1085         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1086                 MAX_SCORE_CACHE_AGE_MILLIS);
1087 
1088         assertThat(ap.getSpeed()).isEqualTo(Speed.FAST);
1089     }
1090 
1091     @Test
testNetworkScoresAreUsedForSpeedLabelGenerationWhenWithinAgeRange()1092     public void testNetworkScoresAreUsedForSpeedLabelGenerationWhenWithinAgeRange() {
1093         long withinRangeTimeMillis =
1094                 SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS - 10000);
1095         AccessPoint ap =
1096                 createApWithFastTimestampedScoredNetworkCache(withinRangeTimeMillis);
1097 
1098         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1099                 MAX_SCORE_CACHE_AGE_MILLIS);
1100 
1101         assertThat(ap.getSpeed()).isEqualTo(Speed.FAST);
1102     }
1103 
1104     @Test
testOldNetworkScoresAreNotUsedForSpeedLabelGeneration()1105     public void testOldNetworkScoresAreNotUsedForSpeedLabelGeneration() {
1106         long tooOldTimeMillis =
1107                 SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1);
1108         AccessPoint ap =
1109                 createApWithFastTimestampedScoredNetworkCache(tooOldTimeMillis);
1110 
1111         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1112                 MAX_SCORE_CACHE_AGE_MILLIS);
1113 
1114         assertThat(ap.getSpeed()).isEqualTo(Speed.NONE);
1115     }
1116 
1117     @Test
testUpdateScoresRefreshesScoredNetworkCacheTimestamps()1118     public void testUpdateScoresRefreshesScoredNetworkCacheTimestamps () {
1119         long tooOldTimeMillis =
1120                 SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1);
1121 
1122         ScoredNetwork scoredNetwork = buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE);
1123         TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork(
1124                 scoredNetwork,
1125                 tooOldTimeMillis);
1126         AccessPoint ap = new TestAccessPointBuilder(mContext)
1127                 .setSsid(TEST_SSID)
1128                 .setBssid(TEST_BSSID)
1129                 .setActive(true)
1130                 .setScoredNetworkCache(
1131                         new ArrayList(Arrays.asList(recentScore)))
1132                 .setScanResults(mScanResults)
1133                 .build();
1134 
1135         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
1136                 .thenReturn(scoredNetwork);
1137 
1138         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1139                 MAX_SCORE_CACHE_AGE_MILLIS);
1140 
1141         // Fast should still be returned since cache was updated with recent time
1142         assertThat(ap.getSpeed()).isEqualTo(Speed.FAST);
1143     }
1144 
1145     @Test
testUpdateScoresRefreshesScoredNetworkCacheWithNewSpeed()1146     public void testUpdateScoresRefreshesScoredNetworkCacheWithNewSpeed () {
1147         long tooOldTimeMillis =
1148                 SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1);
1149 
1150         ScoredNetwork scoredNetwork = buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE);
1151         TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork(
1152                 scoredNetwork,
1153                 tooOldTimeMillis);
1154         AccessPoint ap = new TestAccessPointBuilder(mContext)
1155                 .setSsid(TEST_SSID)
1156                 .setBssid(TEST_BSSID)
1157                 .setActive(true)
1158                 .setScoredNetworkCache(
1159                         new ArrayList(Arrays.asList(recentScore)))
1160                 .setScanResults(mScanResults)
1161                 .build();
1162 
1163         int newSpeed = Speed.MODERATE;
1164         when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
1165                 .thenReturn(buildScoredNetworkWithMockBadgeCurve());
1166         when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) newSpeed);
1167 
1168         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1169                 MAX_SCORE_CACHE_AGE_MILLIS);
1170 
1171         // Fast should still be returned since cache was updated with recent time
1172         assertThat(ap.getSpeed()).isEqualTo(newSpeed);
1173     }
1174 
1175     /**
1176      * Verifies that a Passpoint WifiInfo updates the matching Passpoint AP
1177      */
1178     @Test
testUpdate_passpointWifiInfo_updatesPasspointAccessPoint()1179     public void testUpdate_passpointWifiInfo_updatesPasspointAccessPoint() {
1180         mWifiInfo.setFQDN("fqdn");
1181         mWifiInfo.setProviderFriendlyName("providerFriendlyName");
1182 
1183         WifiConfiguration spyConfig = spy(new WifiConfiguration());
1184         when(spyConfig.isPasspoint()).thenReturn(true);
1185         spyConfig.SSID = TEST_SSID;
1186         spyConfig.BSSID = TEST_BSSID;
1187         spyConfig.FQDN = "fqdn";
1188         spyConfig.providerFriendlyName = "providerFriendlyName";
1189         AccessPoint passpointAp = new AccessPoint(mContext, spyConfig);
1190 
1191         assertThat(passpointAp.update(null, mWifiInfo, null)).isTrue();
1192     }
1193 
1194     /**
1195      * Verifies that a Passpoint WifiInfo does not update a non-Passpoint AP with the same SSID.
1196      */
1197     @Test
testUpdate_passpointWifiInfo_doesNotUpdateNonPasspointAccessPoint()1198     public void testUpdate_passpointWifiInfo_doesNotUpdateNonPasspointAccessPoint() {
1199         mWifiInfo.setFQDN("fqdn");
1200         mWifiInfo.setProviderFriendlyName("providerFriendlyName");
1201 
1202         AccessPoint ap = new TestAccessPointBuilder(mContext)
1203                 .setSsid(TEST_SSID)
1204                 .setBssid(TEST_BSSID)
1205                 .setScanResults(mScanResults)
1206                 .build();
1207 
1208         assertThat(ap.update(null, mWifiInfo, null)).isFalse();
1209     }
1210 
1211     /**
1212      * Verifies that a non-Passpoint WifiInfo does not update a Passpoint AP with the same SSID.
1213      */
1214     @Test
testUpdate_nonPasspointWifiInfo_doesNotUpdatePasspointAccessPoint()1215     public void testUpdate_nonPasspointWifiInfo_doesNotUpdatePasspointAccessPoint() {
1216         WifiConfiguration spyConfig = spy(new WifiConfiguration());
1217         when(spyConfig.isPasspoint()).thenReturn(true);
1218         spyConfig.SSID = TEST_SSID;
1219         spyConfig.BSSID = TEST_BSSID;
1220         spyConfig.FQDN = "fqdn";
1221         spyConfig.providerFriendlyName = "providerFriendlyName";
1222         AccessPoint passpointAp = new AccessPoint(mContext, spyConfig);
1223 
1224         assertThat(passpointAp.update(null, mWifiInfo, null)).isFalse();
1225     }
1226 
1227     /**
1228      * Verifies that an AccessPoint's getKey() is consistent with the overloaded static getKey().
1229      */
1230     @Test
testGetKey_matchesKeysCorrectly()1231     public void testGetKey_matchesKeysCorrectly() {
1232         AccessPoint ap = new AccessPoint(mContext, mScanResults);
1233         assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mContext, mScanResults.get(0)));
1234 
1235         WifiConfiguration spyConfig = spy(new WifiConfiguration());
1236         when(spyConfig.isPasspoint()).thenReturn(true);
1237         spyConfig.FQDN = "fqdn";
1238         AccessPoint passpointAp = new AccessPoint(mContext, spyConfig, mScanResults, null);
1239         assertThat(passpointAp.getKey()).isEqualTo(AccessPoint.getKey(spyConfig));
1240 
1241         PasspointConfiguration passpointConfig = new PasspointConfiguration();
1242         HomeSp homeSp = new HomeSp();
1243         homeSp.setFqdn("fqdn");
1244         homeSp.setFriendlyName("Test Provider");
1245         passpointConfig.setHomeSp(homeSp);
1246         AccessPoint passpointConfigAp = new AccessPoint(mContext, passpointConfig);
1247         assertThat(passpointConfigAp.getKey()).isEqualTo(AccessPoint.getKey("fqdn"));
1248 
1249         OsuProvider provider = createOsuProvider();
1250         AccessPoint osuAp = new AccessPoint(mContext, provider, mScanResults);
1251         assertThat(osuAp.getKey()).isEqualTo(AccessPoint.getKey(provider));
1252     }
1253 
1254     /**
1255      * Test that getKey returns a key of SAE type for a PSK/SAE transition mode ScanResult.
1256      */
1257     @Test
testGetKey_supportSaeTransitionMode_shouldGetSaeKey()1258     public void testGetKey_supportSaeTransitionMode_shouldGetSaeKey() {
1259         ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
1260         scanResult.capabilities =
1261                 "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
1262         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
1263         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1264         StringBuilder key = new StringBuilder();
1265         key.append(AccessPoint.KEY_PREFIX_AP);
1266         key.append(TEST_SSID);
1267         key.append(',');
1268         key.append(AccessPoint.SECURITY_SAE);
1269 
1270         assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
1271     }
1272 
1273     /**
1274      * Test that getKey returns a key of PSK type for a PSK/SAE transition mode ScanResult.
1275      */
1276     @Test
testGetKey_notSupportSaeTransitionMode_shouldGetPskKey()1277     public void testGetKey_notSupportSaeTransitionMode_shouldGetPskKey() {
1278         ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
1279         scanResult.capabilities =
1280                 "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
1281         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
1282         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1283         StringBuilder key = new StringBuilder();
1284         key.append(AccessPoint.KEY_PREFIX_AP);
1285         key.append(TEST_SSID);
1286         key.append(',');
1287         key.append(AccessPoint.SECURITY_PSK);
1288 
1289         assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
1290     }
1291 
1292     /**
1293      * Verifies that the Passpoint AccessPoint constructor creates AccessPoints whose isPasspoint()
1294      * returns true.
1295      */
1296     @Test
testPasspointAccessPointConstructor_createdAccessPointIsPasspoint()1297     public void testPasspointAccessPointConstructor_createdAccessPointIsPasspoint() {
1298         WifiConfiguration spyConfig = spy(new WifiConfiguration());
1299         when(spyConfig.isPasspoint()).thenReturn(true);
1300         AccessPoint passpointAccessPoint = new AccessPoint(mContext, spyConfig,
1301                 mScanResults, mRoamingScans);
1302 
1303         assertThat(passpointAccessPoint.isPasspoint()).isTrue();
1304     }
1305 
1306     /**
1307      * Verifies that Passpoint AccessPoints set their config's SSID to the home scans', and to the
1308      * roaming scans' if no home scans are available.
1309      */
1310     @Test
testSetScanResultsPasspoint_differentiatesHomeAndRoaming()1311     public void testSetScanResultsPasspoint_differentiatesHomeAndRoaming() {
1312         WifiConfiguration spyConfig = spy(new WifiConfiguration());
1313         when(spyConfig.isPasspoint()).thenReturn(true);
1314         AccessPoint passpointAccessPoint = new AccessPoint(mContext, spyConfig,
1315                 mScanResults, mRoamingScans);
1316         assertThat(AccessPoint.removeDoubleQuotes(spyConfig.SSID)).isEqualTo(TEST_SSID);
1317 
1318         passpointAccessPoint.setScanResultsPasspoint(null, mRoamingScans);
1319         assertThat(AccessPoint.removeDoubleQuotes(spyConfig.SSID)).isEqualTo(ROAMING_SSID);
1320 
1321         passpointAccessPoint.setScanResultsPasspoint(mScanResults, null);
1322         assertThat(AccessPoint.removeDoubleQuotes(spyConfig.SSID)).isEqualTo(TEST_SSID);
1323     }
1324 
1325     /**
1326      * Verifies that getScanResults returns both home and roaming scans.
1327      */
1328     @Test
testGetScanResults_showsHomeAndRoamingScans()1329     public void testGetScanResults_showsHomeAndRoamingScans() {
1330         WifiConfiguration spyConfig = spy(new WifiConfiguration());
1331         when(spyConfig.isPasspoint()).thenReturn(true);
1332         AccessPoint passpointAccessPoint = new AccessPoint(mContext, spyConfig,
1333                 mScanResults, mRoamingScans);
1334         Set<ScanResult> fullSet = new ArraySet<>();
1335         fullSet.addAll(mScanResults);
1336         fullSet.addAll(mRoamingScans);
1337         assertThat(passpointAccessPoint.getScanResults()).isEqualTo(fullSet);
1338     }
1339 
1340     /**
1341      * Verifies that the Passpoint AccessPoint takes the ssid of the strongest scan result.
1342      */
1343     @Test
testPasspointAccessPoint_setsBestSsid()1344     public void testPasspointAccessPoint_setsBestSsid() {
1345         WifiConfiguration spyConfig = spy(new WifiConfiguration());
1346         when(spyConfig.isPasspoint()).thenReturn(true);
1347 
1348         String badSsid = "badSsid";
1349         String goodSsid = "goodSsid";
1350         String bestSsid = "bestSsid";
1351         ScanResult badScanResult = createScanResult(badSsid, TEST_BSSID, -100);
1352         ScanResult goodScanResult = createScanResult(goodSsid, TEST_BSSID, -10);
1353         ScanResult bestScanResult = createScanResult(bestSsid, TEST_BSSID, -1);
1354 
1355         AccessPoint passpointAccessPoint = new AccessPoint(mContext, spyConfig,
1356                 Arrays.asList(badScanResult, goodScanResult), null);
1357         assertThat(passpointAccessPoint.getConfig().SSID)
1358                 .isEqualTo(AccessPoint.convertToQuotedString(goodSsid));
1359         passpointAccessPoint.setScanResultsPasspoint(
1360                 Arrays.asList(badScanResult, goodScanResult, bestScanResult), null);
1361         assertThat(passpointAccessPoint.getConfig().SSID)
1362                 .isEqualTo(AccessPoint.convertToQuotedString(bestSsid));
1363     }
1364 
1365     /**
1366      * Verifies that the OSU AccessPoint constructor creates AccessPoints whose isOsuProvider()
1367      * returns true.
1368      */
1369     @Test
testOsuAccessPointConstructor_createdAccessPointIsOsuProvider()1370     public void testOsuAccessPointConstructor_createdAccessPointIsOsuProvider() {
1371         AccessPoint osuAccessPoint = new AccessPoint(mContext, createOsuProvider(),
1372                 mScanResults);
1373 
1374         assertThat(osuAccessPoint.isOsuProvider()).isTrue();
1375     }
1376 
1377     /**
1378      * Verifies that the summary of an OSU entry only shows the tap_to_sign_up string.
1379      */
1380     @Test
testOsuAccessPointSummary_showsTapToSignUp()1381     public void testOsuAccessPointSummary_showsTapToSignUp() {
1382         AccessPoint osuAccessPoint = new AccessPoint(mContext, createOsuProvider(),
1383                 mScanResults);
1384 
1385         assertThat(osuAccessPoint.getSummary())
1386                 .isEqualTo(mContext.getString(R.string.tap_to_sign_up));
1387     }
1388 
1389     /**
1390      * Verifies that the summary of an OSU entry updates based on provisioning status.
1391      */
1392     @Test
testOsuAccessPointSummary_showsProvisioningUpdates()1393     public void testOsuAccessPointSummary_showsProvisioningUpdates() {
1394         OsuProvider provider = createOsuProvider();
1395         Context spyContext = spy(new ContextWrapper(mContext));
1396         when(spyContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1397         Map<OsuProvider, PasspointConfiguration> osuProviderConfigMap = new HashMap<>();
1398         osuProviderConfigMap.put(provider, null);
1399         when(mMockWifiManager.getMatchingPasspointConfigsForOsuProviders(
1400                 Collections.singleton(provider))).thenReturn(osuProviderConfigMap);
1401         AccessPoint osuAccessPoint = new AccessPoint(spyContext, provider,
1402                 mScanResults);
1403 
1404         osuAccessPoint.setListener(mMockAccessPointListener);
1405 
1406         AccessPoint.AccessPointProvisioningCallback provisioningCallback =
1407                 osuAccessPoint.new AccessPointProvisioningCallback();
1408 
1409         int[] openingProviderStatuses = {
1410                 ProvisioningCallback.OSU_STATUS_AP_CONNECTING,
1411                 ProvisioningCallback.OSU_STATUS_AP_CONNECTED,
1412                 ProvisioningCallback.OSU_STATUS_SERVER_CONNECTING,
1413                 ProvisioningCallback.OSU_STATUS_SERVER_VALIDATED,
1414                 ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED,
1415                 ProvisioningCallback.OSU_STATUS_INIT_SOAP_EXCHANGE,
1416                 ProvisioningCallback.OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE
1417         };
1418         int[] completingSignUpStatuses = {
1419                 ProvisioningCallback.OSU_STATUS_REDIRECT_RESPONSE_RECEIVED,
1420                 ProvisioningCallback.OSU_STATUS_SECOND_SOAP_EXCHANGE,
1421                 ProvisioningCallback.OSU_STATUS_THIRD_SOAP_EXCHANGE,
1422                 ProvisioningCallback.OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS,
1423         };
1424 
1425         for (int status : openingProviderStatuses) {
1426             provisioningCallback.onProvisioningStatus(status);
1427             assertThat(osuAccessPoint.getSummary())
1428                     .isEqualTo(String.format(mContext.getString(R.string.osu_opening_provider),
1429                             OSU_FRIENDLY_NAME));
1430         }
1431 
1432         provisioningCallback.onProvisioningFailure(0);
1433         assertThat(osuAccessPoint.getSummary())
1434                 .isEqualTo(mContext.getString(R.string.osu_connect_failed));
1435 
1436         for (int status : completingSignUpStatuses) {
1437             provisioningCallback.onProvisioningStatus(status);
1438             assertThat(osuAccessPoint.getSummary())
1439                     .isEqualTo(mContext.getString(R.string.osu_completing_sign_up));
1440         }
1441 
1442         provisioningCallback.onProvisioningFailure(0);
1443         assertThat(osuAccessPoint.getSummary())
1444                 .isEqualTo(mContext.getString(R.string.osu_sign_up_failed));
1445 
1446         provisioningCallback.onProvisioningComplete();
1447         assertThat(osuAccessPoint.getSummary())
1448                 .isEqualTo(mContext.getString(R.string.osu_sign_up_complete));
1449     }
1450 
1451     /**
1452      * Verifies that after provisioning through an OSU provider, we connect to the freshly
1453      * provisioned network.
1454      */
1455     @Test
testOsuAccessPoint_connectsAfterProvisioning()1456     public void testOsuAccessPoint_connectsAfterProvisioning() {
1457         // Set up mock for WifiManager.getAllMatchingWifiConfigs
1458         WifiConfiguration config = new WifiConfiguration();
1459         config.FQDN = "fqdn";
1460         Map<Integer, List<ScanResult>> scanMapping = new HashMap<>();
1461         scanMapping.put(WifiManager.PASSPOINT_HOME_NETWORK, mScanResults);
1462         Pair<WifiConfiguration, Map<Integer, List<ScanResult>>> configMapPair =
1463                 new Pair<>(config, scanMapping);
1464         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingWifiConfig =
1465                 new ArrayList<>();
1466         matchingWifiConfig.add(configMapPair);
1467         when(mMockWifiManager.getAllMatchingWifiConfigs(any())).thenReturn(matchingWifiConfig);
1468 
1469         // Set up mock for WifiManager.getMatchingPasspointConfigsForOsuProviders
1470         OsuProvider provider = createOsuProvider();
1471         PasspointConfiguration passpointConfig = new PasspointConfiguration();
1472         HomeSp homeSp = new HomeSp();
1473         homeSp.setFqdn("fqdn");
1474         homeSp.setFriendlyName("Test Provider");
1475         passpointConfig.setHomeSp(homeSp);
1476         Map<OsuProvider, PasspointConfiguration> osuProviderConfigMap = new HashMap<>();
1477         osuProviderConfigMap.put(provider, passpointConfig);
1478         when(mMockWifiManager
1479                 .getMatchingPasspointConfigsForOsuProviders(Collections.singleton(provider)))
1480                 .thenReturn(osuProviderConfigMap);
1481 
1482         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1483 
1484         AccessPoint osuAccessPoint = new AccessPoint(mMockContext, provider, mScanResults);
1485         osuAccessPoint.setListener(mMockAccessPointListener);
1486 
1487         AccessPoint.AccessPointProvisioningCallback provisioningCallback =
1488                 osuAccessPoint.new AccessPointProvisioningCallback();
1489         provisioningCallback.onProvisioningComplete();
1490 
1491         verify(mMockWifiManager).connect(any(), any());
1492     }
1493 
1494     /**
1495      * Verifies that after provisioning through an OSU provider, we call the connect listener's
1496      * onFailure() method if we cannot find the network we just provisioned.
1497      */
1498     @Test
testOsuAccessPoint_noMatchingConfigsAfterProvisioning_callsOnFailure()1499     public void testOsuAccessPoint_noMatchingConfigsAfterProvisioning_callsOnFailure() {
1500         // Set up mock for WifiManager.getAllMatchingWifiConfigs
1501         when(mMockWifiManager.getAllMatchingWifiConfigs(any())).thenReturn(new ArrayList<>());
1502 
1503         // Set up mock for WifiManager.getMatchingPasspointConfigsForOsuProviders
1504         OsuProvider provider = createOsuProvider();
1505         PasspointConfiguration passpointConfig = new PasspointConfiguration();
1506         HomeSp homeSp = new HomeSp();
1507         homeSp.setFqdn("fqdn");
1508         homeSp.setFriendlyName("Test Provider");
1509         passpointConfig.setHomeSp(homeSp);
1510         Map<OsuProvider, PasspointConfiguration> osuProviderConfigMap = new HashMap<>();
1511         osuProviderConfigMap.put(provider, passpointConfig);
1512         when(mMockWifiManager
1513                 .getMatchingPasspointConfigsForOsuProviders(Collections.singleton(provider)))
1514                 .thenReturn(osuProviderConfigMap);
1515 
1516         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1517 
1518         AccessPoint osuAccessPoint = new AccessPoint(mMockContext, provider, mScanResults);
1519         osuAccessPoint.setListener(mMockAccessPointListener);
1520         osuAccessPoint.startOsuProvisioning(mMockConnectListener);
1521 
1522         AccessPoint.AccessPointProvisioningCallback provisioningCallback =
1523                 osuAccessPoint.new AccessPointProvisioningCallback();
1524         provisioningCallback.onProvisioningComplete();
1525 
1526         verify(mMockConnectListener).onFailure(anyInt());
1527     }
1528 
1529     /**
1530      * Verifies that isOpenNetwork returns true for SECURITY_NONE, SECURITY_OWE, and
1531      * SECURITY_OWE_TRANSITION.
1532      */
1533     @Test
testIsOpenNetwork_returnValidResult()1534     public void testIsOpenNetwork_returnValidResult() {
1535         final Bundle bundle = new Bundle();
1536         AccessPoint ap;
1537 
1538         for (int i = 0; i < AccessPoint.SECURITY_MAX_VAL; i++) {
1539             bundle.putInt("key_security", i);
1540             ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
1541 
1542             if (i == AccessPoint.SECURITY_NONE || i == AccessPoint.SECURITY_OWE) {
1543                 assertThat(ap.isOpenNetwork()).isTrue();
1544             } else {
1545                 assertThat(ap.isOpenNetwork()).isFalse();
1546             }
1547         }
1548     }
1549 
1550     /**
1551      * Verifies that matches(AccessPoint other) matches a PSK/SAE transition mode AP to a PSK or a
1552      * SAE AP.
1553      */
1554     @Test
testMatches1_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly()1555     public void testMatches1_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
1556         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1557         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
1558         AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
1559 
1560         // Transition mode AP matches a SAE AP.
1561         AccessPoint saeAccessPoint = new TestAccessPointBuilder(mContext)
1562                 .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
1563                 .setSecurity(AccessPoint.SECURITY_SAE)
1564                 .build();
1565         assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isTrue();
1566 
1567         // Transition mode AP matches a PSK AP.
1568         AccessPoint pskAccessPoint = new TestAccessPointBuilder(mContext)
1569                 .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
1570                 .setSecurity(AccessPoint.SECURITY_PSK)
1571                 .build();
1572 
1573         assertThat(pskSaeTransitionModeAp.matches(pskAccessPoint)).isTrue();
1574 
1575         // Transition mode AP does not match a SAE AP if the device does not support SAE.
1576         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
1577         pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
1578         saeAccessPoint = new TestAccessPointBuilder(mContext)
1579             .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
1580             .setSecurity(AccessPoint.SECURITY_SAE)
1581             .build();
1582 
1583         assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isFalse();
1584     }
1585 
1586     /**
1587      * Verifies that matches(WifiConfiguration config) matches a PSK/SAE transition mode AP to a PSK
1588      * or a SAE WifiConfiguration.
1589      */
1590     @Test
testMatches2_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly()1591     public void testMatches2_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
1592         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1593         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
1594         AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
1595 
1596         // Transition mode AP matches a SAE WifiConfiguration.
1597         WifiConfiguration saeConfig = new WifiConfiguration();
1598         saeConfig.SSID = TEST_SSID;
1599         saeConfig.allowedKeyManagement.set(KeyMgmt.SAE);
1600 
1601         assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isTrue();
1602 
1603         // Transition mode AP matches a PSK WifiConfiguration.
1604         WifiConfiguration pskConfig = new WifiConfiguration();
1605         pskConfig.SSID = TEST_SSID;
1606         pskConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
1607 
1608         assertThat(pskSaeTransitionModeAp.matches(pskConfig)).isTrue();
1609 
1610         // Transition mode AP does not matches a SAE WifiConfiguration if the device does not
1611         // support SAE.
1612         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
1613         pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
1614 
1615         assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isFalse();
1616     }
1617 
1618     /**
1619      * Verifies that matches(ScanResult scanResult) matches a PSK/SAE transition mode AP to a PSK
1620      * or a SAE ScanResult.
1621      */
1622     @Test
testMatches3_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly()1623     public void testMatches3_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
1624         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1625         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
1626         AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
1627 
1628         // Transition mode AP matches a SAE ScanResult.
1629         ScanResult saeScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
1630                 TEST_BSSID, DEFAULT_RSSI);
1631         saeScanResult.capabilities = "[SAE-CCMP][ESS][WPS]";
1632 
1633         assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isTrue();
1634 
1635         // Transition mode AP matches a PSK ScanResult.
1636         ScanResult pskScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
1637                 TEST_BSSID, DEFAULT_RSSI);
1638         pskScanResult.capabilities = "[RSN-PSK-CCMP][ESS][WPS]";
1639 
1640         assertThat(pskSaeTransitionModeAp.matches(pskScanResult)).isTrue();
1641 
1642         // Transition mode AP does not matches a SAE ScanResult if the device does not support SAE.
1643         when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
1644         pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
1645 
1646         assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isFalse();
1647     }
1648 
1649     @Test
testGetSecurityString_oweTransitionMode_shouldReturnCorrectly()1650     public void testGetSecurityString_oweTransitionMode_shouldReturnCorrectly() {
1651         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1652         when(mMockWifiManager.isEnhancedOpenSupported()).thenReturn(true);
1653         AccessPoint oweTransitionModeAp = getOweTransitionModeAp();
1654 
1655         assertThat(oweTransitionModeAp.getSecurityString(true /* concise */))
1656                 .isEqualTo(mContext.getString(R.string.wifi_security_short_none_owe));
1657         assertThat(oweTransitionModeAp.getSecurityString(false /* concise */))
1658                 .isEqualTo(mContext.getString(R.string.wifi_security_none_owe));
1659     }
1660 
getPskSaeTransitionModeAp()1661     private AccessPoint getPskSaeTransitionModeAp() {
1662         ScanResult scanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
1663                 TEST_BSSID, DEFAULT_RSSI);
1664         scanResult.capabilities =
1665                 "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
1666         return new TestAccessPointBuilder(mMockContext)
1667                 .setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
1668                 .build();
1669     }
1670 
getOweTransitionModeAp()1671     private AccessPoint getOweTransitionModeAp() {
1672         ScanResult scanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
1673                 TEST_BSSID, DEFAULT_RSSI);
1674         scanResult.capabilities = "[OWE_TRANSITION]";
1675         return new TestAccessPointBuilder(mContext)
1676                 .setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
1677                 .build();
1678     }
1679 
1680     @Test
testGenerateOpenNetworkConfig_oweNotSupported_shouldGetCorrectSecurity()1681     public void testGenerateOpenNetworkConfig_oweNotSupported_shouldGetCorrectSecurity() {
1682         when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
1683         AccessPoint oweAccessPoint = new TestAccessPointBuilder(mMockContext)
1684                 .setSecurity(AccessPoint.SECURITY_OWE).build();
1685         AccessPoint noneAccessPoint = new TestAccessPointBuilder(mMockContext)
1686                 .setSecurity(AccessPoint.SECURITY_NONE).build();
1687 
1688         oweAccessPoint.generateOpenNetworkConfig();
1689         noneAccessPoint.generateOpenNetworkConfig();
1690 
1691         assertThat(oweAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.NONE)).isFalse();
1692         assertThat(oweAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.OWE)).isTrue();
1693         assertThat(noneAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.NONE)).isTrue();
1694         assertThat(noneAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.OWE)).isFalse();
1695     }
1696 }
1697