• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION;
4 import static android.os.Build.VERSION_CODES.LOLLIPOP;
5 import static android.os.Build.VERSION_CODES.Q;
6 import static android.os.Build.VERSION_CODES.R;
7 import static android.os.Build.VERSION_CODES.S;
8 import static android.os.Build.VERSION_CODES.TIRAMISU;
9 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
10 import static com.google.common.truth.Truth.assertThat;
11 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
12 import static java.util.concurrent.TimeUnit.MINUTES;
13 import static org.junit.Assert.assertThrows;
14 import static org.junit.Assert.fail;
15 import static org.mockito.ArgumentMatchers.eq;
16 import static org.mockito.Mockito.mock;
17 import static org.mockito.Mockito.verify;
18 import static org.mockito.Mockito.verifyNoMoreInteractions;
19 import static org.robolectric.Shadows.shadowOf;
20 
21 import android.app.Application;
22 import android.app.admin.DeviceAdminService;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.net.ConnectivityManager;
28 import android.net.DhcpInfo;
29 import android.net.MacAddress;
30 import android.net.NetworkInfo;
31 import android.net.wifi.ScanResult;
32 import android.net.wifi.SoftApConfiguration;
33 import android.net.wifi.WifiConfiguration;
34 import android.net.wifi.WifiInfo;
35 import android.net.wifi.WifiManager;
36 import android.net.wifi.WifiManager.AddNetworkResult;
37 import android.net.wifi.WifiManager.LocalOnlyConnectionFailureListener;
38 import android.net.wifi.WifiManager.MulticastLock;
39 import android.net.wifi.WifiManager.PnoScanResultsCallback;
40 import android.net.wifi.WifiNetworkSpecifier;
41 import android.net.wifi.WifiSsid;
42 import android.net.wifi.WifiUsabilityStatsEntry;
43 import android.os.Build;
44 import android.util.Pair;
45 import androidx.test.ext.junit.runners.AndroidJUnit4;
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.concurrent.BlockingQueue;
49 import java.util.concurrent.ExecutorService;
50 import java.util.concurrent.Executors;
51 import java.util.concurrent.LinkedBlockingQueue;
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.ArgumentCaptor;
56 import org.robolectric.RuntimeEnvironment;
57 import org.robolectric.annotation.Config;
58 import org.robolectric.shadow.api.Shadow;
59 import org.robolectric.util.ReflectionHelpers;
60 import org.robolectric.versioning.AndroidVersions.U;
61 
62 @RunWith(AndroidJUnit4.class)
63 public class ShadowWifiManagerTest {
64   private WifiManager wifiManager;
65 
66   @Before
setUp()67   public void setUp() throws Exception {
68     wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
69   }
70 
71   @Test
shouldReturnWifiInfo()72   public void shouldReturnWifiInfo() {
73     assertThat(wifiManager.getConnectionInfo().getClass()).isEqualTo(WifiInfo.class);
74   }
75 
76   @Test
setWifiInfo_shouldUpdateWifiInfo()77   public void setWifiInfo_shouldUpdateWifiInfo() {
78     WifiInfo wifiInfo = newWifiInfo();
79     shadowOf(wifiManager).setConnectionInfo(wifiInfo);
80     assertThat(wifiManager.getConnectionInfo()).isSameInstanceAs(wifiInfo);
81   }
82 
newWifiInfo()83   private static WifiInfo newWifiInfo() {
84     if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) {
85       return new WifiInfo();
86     } else {
87       return ReflectionHelpers.callConstructor(WifiInfo.class);
88     }
89   }
90 
91   @Test
setWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted()92   public void setWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() {
93     shadowOf(wifiManager).setAccessWifiStatePermission(false);
94     try {
95       wifiManager.setWifiEnabled(true);
96       fail("SecurityException not thrown");
97     } catch (SecurityException e) {
98       // expected
99     }
100   }
101 
102   @Test
isWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted()103   public void isWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() {
104     shadowOf(wifiManager).setAccessWifiStatePermission(false);
105     try {
106       wifiManager.isWifiEnabled();
107       fail("SecurityException not thrown");
108     } catch (SecurityException e) {
109       // expected
110     }
111   }
112 
113   @Test
getWifiState_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted()114   public void getWifiState_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() {
115     shadowOf(wifiManager).setAccessWifiStatePermission(false);
116     try {
117       wifiManager.getWifiState();
118       fail("SecurityException not thrown");
119     } catch (SecurityException e) {
120       // expected
121     }
122   }
123 
124   @Test
125   public void
getConnectionInfo_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted()126       getConnectionInfo_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() {
127     shadowOf(wifiManager).setAccessWifiStatePermission(false);
128     try {
129       wifiManager.getConnectionInfo();
130       fail("SecurityException not thrown");
131     } catch (SecurityException e) {
132       // expected
133     }
134   }
135 
136   @Test
getWifiState()137   public void getWifiState() {
138     wifiManager.setWifiEnabled(true);
139     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLED);
140 
141     wifiManager.setWifiEnabled(false);
142     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_DISABLED);
143   }
144 
145   @Test
startScan()146   public void startScan() {
147     // By default startScan() succeeds.
148     assertThat(wifiManager.startScan()).isTrue();
149 
150     shadowOf(wifiManager).setStartScanSucceeds(true);
151     assertThat(wifiManager.startScan()).isTrue();
152 
153     shadowOf(wifiManager).setStartScanSucceeds(false);
154     assertThat(wifiManager.startScan()).isFalse();
155   }
156 
157   @Test
getIsScanAlwaysAvailable()158   public void getIsScanAlwaysAvailable() {
159     shadowOf(wifiManager).setIsScanAlwaysAvailable(true);
160     assertThat(wifiManager.isScanAlwaysAvailable()).isEqualTo(true);
161 
162     shadowOf(wifiManager).setIsScanAlwaysAvailable(false);
163     assertThat(wifiManager.isScanAlwaysAvailable()).isEqualTo(false);
164   }
165 
166   @Test
shouldEnableNetworks()167   public void shouldEnableNetworks() {
168     wifiManager.enableNetwork(666, true);
169     Pair<Integer, Boolean> lastEnabled = shadowOf(wifiManager).getLastEnabledNetwork();
170     assertThat(lastEnabled).isEqualTo(new Pair<>(666, true));
171 
172     wifiManager.enableNetwork(777, false);
173     lastEnabled = shadowOf(wifiManager).getLastEnabledNetwork();
174     assertThat(lastEnabled).isEqualTo(new Pair<>(777, false));
175 
176     boolean enabledNetwork = shadowOf(wifiManager).isNetworkEnabled(666);
177     assertThat(enabledNetwork).isTrue();
178 
179     enabledNetwork = shadowOf(wifiManager).isNetworkEnabled(777);
180     assertThat(enabledNetwork).isTrue();
181   }
182 
183   @Test
shouldDisableNetwork()184   public void shouldDisableNetwork() {
185     wifiManager.enableNetwork(666, true);
186     boolean enabledNetwork = shadowOf(wifiManager).isNetworkEnabled(666);
187     assertThat(enabledNetwork).isTrue();
188 
189     wifiManager.disableNetwork(666);
190     enabledNetwork = shadowOf(wifiManager).isNetworkEnabled(666);
191     assertThat(enabledNetwork).isFalse();
192   }
193 
194   @Test
shouldReturnSetScanResults()195   public void shouldReturnSetScanResults() {
196     List<ScanResult> scanResults = new ArrayList<>();
197     shadowOf(wifiManager).setScanResults(scanResults);
198     assertThat(wifiManager.getScanResults()).isSameInstanceAs(scanResults);
199   }
200 
201   @Test
shouldReturnDhcpInfo()202   public void shouldReturnDhcpInfo() {
203     DhcpInfo dhcpInfo = new DhcpInfo();
204     shadowOf(wifiManager).setDhcpInfo(dhcpInfo);
205     assertThat(wifiManager.getDhcpInfo()).isSameInstanceAs(dhcpInfo);
206   }
207 
208   @Test
shouldRecordTheLastAddedNetwork()209   public void shouldRecordTheLastAddedNetwork() {
210     WifiConfiguration wifiConfiguration = new WifiConfiguration();
211     wifiConfiguration.networkId = -1;
212     int networkId = wifiManager.addNetwork(wifiConfiguration);
213     assertThat(networkId).isEqualTo(0);
214     assertThat(wifiManager.getConfiguredNetworks().get(0)).isNotSameInstanceAs(wifiConfiguration);
215     assertThat(wifiConfiguration.networkId).isEqualTo(-1);
216     assertThat(wifiManager.getConfiguredNetworks().get(0).networkId).isEqualTo(0);
217     assertThat(wifiManager.addNetwork(/* wifiConfiguration= */ null)).isEqualTo(-1);
218 
219     WifiConfiguration anotherConfig = new WifiConfiguration();
220     assertThat(wifiManager.addNetwork(anotherConfig)).isEqualTo(1);
221     assertThat(anotherConfig.networkId).isEqualTo(-1);
222     assertThat(wifiManager.getConfiguredNetworks().get(1).networkId).isEqualTo(1);
223   }
224 
225   @Test
updateNetwork_shouldReplaceNetworks()226   public void updateNetwork_shouldReplaceNetworks() {
227     WifiConfiguration wifiConfiguration = new WifiConfiguration();
228     wifiConfiguration.networkId = -1;
229     wifiManager.addNetwork(wifiConfiguration);
230 
231     WifiConfiguration anotherConfig = new WifiConfiguration();
232     int networkId = wifiManager.addNetwork(anotherConfig);
233 
234     assertThat(networkId).isEqualTo(1);
235     WifiConfiguration configuration = new WifiConfiguration();
236     configuration.networkId = networkId;
237     configuration.priority = 44;
238 
239     assertThat(wifiManager.updateNetwork(configuration)).isEqualTo(networkId);
240     List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
241     assertThat(configuredNetworks.size()).isEqualTo(2);
242     assertThat(configuration.priority).isEqualTo(44);
243     assertThat(configuredNetworks.get(1).priority).isEqualTo(44);
244   }
245 
246   @Test
updateNetworkTests_permissions()247   public void updateNetworkTests_permissions() {
248     int networkId = 1;
249     WifiConfiguration wifiConfiguration = new WifiConfiguration();
250     wifiConfiguration.networkId = networkId;
251 
252     // By default we should have permission to update networks.
253     assertThat(wifiManager.updateNetwork(wifiConfiguration)).isEqualTo(networkId);
254 
255     // If we don't have permission to update, updateNetwork will return -1.
256     shadowOf(wifiManager).setUpdateNetworkPermission(networkId, /* hasPermission= */ false);
257     assertThat(wifiManager.updateNetwork(wifiConfiguration)).isEqualTo(-1);
258 
259     // Ensure updates can occur if permission is restored.
260     shadowOf(wifiManager).setUpdateNetworkPermission(networkId, /* hasPermission= */ true);
261     assertThat(wifiManager.updateNetwork(wifiConfiguration)).isEqualTo(networkId);
262   }
263 
264   @Test
removeNetwork()265   public void removeNetwork() {
266     WifiConfiguration wifiConfiguration = new WifiConfiguration();
267     wifiConfiguration.networkId = 123;
268     wifiManager.addNetwork(wifiConfiguration);
269 
270     List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
271     assertThat(list.size()).isEqualTo(1);
272 
273     wifiManager.removeNetwork(0);
274 
275     list = wifiManager.getConfiguredNetworks();
276     assertThat(list.size()).isEqualTo(0);
277   }
278 
279   @Test
280   @Config(minSdk = S)
addNetworkPrivileged_nullConfig_shouldThrowIllegalArgumentException()281   public void addNetworkPrivileged_nullConfig_shouldThrowIllegalArgumentException() {
282     assertThrows(IllegalArgumentException.class, () -> wifiManager.addNetworkPrivileged(null));
283   }
284 
285   @Test
286   @Config(minSdk = S)
addNetworkPrivileged_nonNullConfig_shouldAddNetworkSuccessfully()287   public void addNetworkPrivileged_nonNullConfig_shouldAddNetworkSuccessfully() {
288     WifiConfiguration wifiConfiguration = new WifiConfiguration();
289 
290     AddNetworkResult addNetworkResult = wifiManager.addNetworkPrivileged(wifiConfiguration);
291 
292     assertThat(addNetworkResult).isNotNull();
293     assertThat(addNetworkResult.statusCode).isEqualTo(AddNetworkResult.STATUS_SUCCESS);
294     assertThat(wifiManager.getConfiguredNetworks()).hasSize(1);
295   }
296 
297   @Test
298   @Config(minSdk = S)
299   public void
getCallerConfiguredNetworks_noAccessWifiStatePermission_shouldThrowSecurityException()300       getCallerConfiguredNetworks_noAccessWifiStatePermission_shouldThrowSecurityException() {
301     shadowOf(wifiManager).setAccessWifiStatePermission(false);
302 
303     assertThrows(SecurityException.class, () -> wifiManager.getCallerConfiguredNetworks());
304   }
305 
306   @Test
307   @Config(minSdk = S)
getCallerConfiguredNetworks_noNetworksConfigured_returnsEmptyList()308   public void getCallerConfiguredNetworks_noNetworksConfigured_returnsEmptyList() {
309     assertThat(wifiManager.getCallerConfiguredNetworks()).isEmpty();
310   }
311 
312   @Test
313   @Config(minSdk = S)
getCallerConfiguredNetworks_networksAddedAndRemoved_returnsConfiguredNetworks()314   public void getCallerConfiguredNetworks_networksAddedAndRemoved_returnsConfiguredNetworks() {
315     WifiConfiguration wifiConfiguration = new WifiConfiguration();
316     wifiManager.addNetwork(wifiConfiguration);
317 
318     assertThat(wifiManager.getCallerConfiguredNetworks()).hasSize(1);
319 
320     wifiManager.removeNetwork(0);
321 
322     assertThat(wifiManager.getCallerConfiguredNetworks()).isEmpty();
323   }
324 
325   @Test
326   @Config(minSdk = S)
327   public void
removeNonCallerConfiguredNetworks_noChangeWifiStatePermission_shouldThrowSecurityException()328       removeNonCallerConfiguredNetworks_noChangeWifiStatePermission_shouldThrowSecurityException() {
329     setDeviceOwner();
330     shadowOf(wifiManager).setChangeWifiStatePermission(false);
331 
332     assertThrows(SecurityException.class, () -> wifiManager.removeNonCallerConfiguredNetworks());
333   }
334 
335   @Test
336   @Config(minSdk = S)
removeNonCallerConfiguredNetworks_notDeviceOwner_shouldThrowSecurityException()337   public void removeNonCallerConfiguredNetworks_notDeviceOwner_shouldThrowSecurityException() {
338     assertThrows(SecurityException.class, () -> wifiManager.removeNonCallerConfiguredNetworks());
339   }
340 
341   @Test
342   @Config(minSdk = S)
removeNonCallerConfiguredNetworks_noConfiguredNetworks_returnsFalse()343   public void removeNonCallerConfiguredNetworks_noConfiguredNetworks_returnsFalse() {
344     setDeviceOwner();
345 
346     assertThat(wifiManager.removeNonCallerConfiguredNetworks()).isFalse();
347   }
348 
349   @Test
350   @Config(minSdk = S)
removeNonCallerConfiguredNetworks_hasConfiguredNetworks_removesConfiguredNetworks()351   public void removeNonCallerConfiguredNetworks_hasConfiguredNetworks_removesConfiguredNetworks() {
352     setDeviceOwner();
353     wifiManager.addNetwork(new WifiConfiguration());
354     wifiManager.addNetwork(new WifiConfiguration());
355 
356     assertThat(wifiManager.removeNonCallerConfiguredNetworks()).isTrue();
357     assertThat(wifiManager.getConfiguredNetworks()).isEmpty();
358   }
359 
360   @Test
361   @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
getPrivilegedConfiguredNetworks_shouldReturnConfiguredNetworks()362   public void getPrivilegedConfiguredNetworks_shouldReturnConfiguredNetworks() {
363     WifiConfiguration wifiConfiguration = new WifiConfiguration();
364     wifiConfiguration.networkId = 123;
365     wifiManager.addNetwork(wifiConfiguration);
366 
367     List<WifiConfiguration> list = wifiManager.getPrivilegedConfiguredNetworks();
368     assertThat(list.size()).isEqualTo(1);
369 
370     wifiManager.removeNetwork(0);
371 
372     list = wifiManager.getPrivilegedConfiguredNetworks();
373     assertThat(list.size()).isEqualTo(0);
374   }
375 
376   @Test
updateNetwork_shouldRejectNullandNewConfigs()377   public void updateNetwork_shouldRejectNullandNewConfigs() {
378     WifiConfiguration config = new WifiConfiguration();
379     config.networkId = -1;
380     assertThat(wifiManager.updateNetwork(config)).isEqualTo(-1);
381     assertThat(wifiManager.updateNetwork(null)).isEqualTo(-1);
382     assertThat(wifiManager.getConfiguredNetworks()).isEmpty();
383   }
384 
385   @Test
shouldSaveConfigurations()386   public void shouldSaveConfigurations() {
387     assertThat(wifiManager.saveConfiguration()).isTrue();
388     assertThat(shadowOf(wifiManager).wasConfigurationSaved()).isTrue();
389   }
390 
391   @Test
shouldCreateWifiLock()392   public void shouldCreateWifiLock() {
393     assertThat(wifiManager.createWifiLock("TAG")).isNotNull();
394     assertThat(wifiManager.createWifiLock(1, "TAG")).isNotNull();
395   }
396 
397   @Test
wifiLockAcquireIncreasesActiveLockCount()398   public void wifiLockAcquireIncreasesActiveLockCount() {
399     WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG");
400     assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0);
401     lock.acquire();
402     assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(1);
403     lock.release();
404     assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0);
405   }
406 
407   @Test
multicastLockAcquireIncreasesActiveLockCount()408   public void multicastLockAcquireIncreasesActiveLockCount() {
409     MulticastLock lock = wifiManager.createMulticastLock("TAG");
410     assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0);
411     lock.acquire();
412     assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(1);
413     lock.release();
414     assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0);
415   }
416 
417   @Test
shouldAcquireAndReleaseWifilockRefCounted()418   public void shouldAcquireAndReleaseWifilockRefCounted() {
419     WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG");
420     lock.acquire();
421     lock.acquire();
422     assertThat(lock.isHeld()).isTrue();
423     lock.release();
424     assertThat(lock.isHeld()).isTrue();
425     lock.release();
426     assertThat(lock.isHeld()).isFalse();
427   }
428 
429   @Test
shouldAcquireAndReleaseWifilockNonRefCounted()430   public void shouldAcquireAndReleaseWifilockNonRefCounted() {
431     WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG");
432     lock.setReferenceCounted(false);
433     lock.acquire();
434     assertThat(lock.isHeld()).isTrue();
435     lock.acquire();
436     assertThat(lock.isHeld()).isTrue();
437     lock.release();
438     assertThat(lock.isHeld()).isFalse();
439   }
440 
441   @Test
shouldThrowRuntimeExceptionIfWifiLockisUnderlocked()442   public void shouldThrowRuntimeExceptionIfWifiLockisUnderlocked() {
443     WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG");
444     try {
445       lock.release();
446       fail("RuntimeException not thrown");
447     } catch (RuntimeException e) {
448       // expected
449     }
450   }
451 
452   @Test
shouldThrowUnsupportedOperationIfWifiLockisOverlocked()453   public void shouldThrowUnsupportedOperationIfWifiLockisOverlocked() {
454     WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG");
455     try {
456       for (int i = 0; i < ShadowWifiManager.ShadowWifiLock.MAX_ACTIVE_LOCKS; i++) {
457         lock.acquire();
458       }
459       fail("UnsupportedOperationException not thrown");
460     } catch (UnsupportedOperationException e) {
461       // expected
462     }
463   }
464 
465   @Test
shouldCreateMulticastLock()466   public void shouldCreateMulticastLock() {
467     assertThat(wifiManager.createMulticastLock("TAG")).isNotNull();
468   }
469 
470   @Test
shouldAcquireAndReleaseMulticastLockRefCounted()471   public void shouldAcquireAndReleaseMulticastLockRefCounted() {
472     MulticastLock lock = wifiManager.createMulticastLock("TAG");
473     lock.acquire();
474     lock.acquire();
475     assertThat(lock.isHeld()).isTrue();
476     lock.release();
477     assertThat(lock.isHeld()).isTrue();
478     lock.release();
479     assertThat(lock.isHeld()).isFalse();
480   }
481 
482   @Test
shouldAcquireAndReleaseMulticastLockNonRefCounted()483   public void shouldAcquireAndReleaseMulticastLockNonRefCounted() {
484     MulticastLock lock = wifiManager.createMulticastLock("TAG");
485     lock.setReferenceCounted(false);
486     lock.acquire();
487     assertThat(lock.isHeld()).isTrue();
488     lock.acquire();
489     assertThat(lock.isHeld()).isTrue();
490     lock.release();
491     assertThat(lock.isHeld()).isFalse();
492   }
493 
494   @Test
shouldThrowRuntimeExceptionIfMulticastLockisUnderlocked()495   public void shouldThrowRuntimeExceptionIfMulticastLockisUnderlocked() {
496     MulticastLock lock = wifiManager.createMulticastLock("TAG");
497     try {
498       lock.release();
499       fail("Expected exception");
500     } catch (RuntimeException expected) {
501     }
502     ;
503   }
504 
505   @Test
shouldThrowUnsupportedOperationIfMulticastLockisOverlocked()506   public void shouldThrowUnsupportedOperationIfMulticastLockisOverlocked() {
507     MulticastLock lock = wifiManager.createMulticastLock("TAG");
508     try {
509       for (int i = 0; i < ShadowWifiManager.ShadowMulticastLock.MAX_ACTIVE_LOCKS; i++) {
510         lock.acquire();
511       }
512       fail("Expected exception");
513     } catch (UnsupportedOperationException e) {
514       // expected
515     }
516   }
517 
518   @Test
shouldCalculateSignalLevelSetBefore()519   public void shouldCalculateSignalLevelSetBefore() {
520     ShadowWifiManager.setSignalLevelInPercent(0.5f);
521     assertThat(WifiManager.calculateSignalLevel(0, 5)).isEqualTo(2);
522     assertThat(WifiManager.calculateSignalLevel(2, 5)).isEqualTo(2);
523 
524     ShadowWifiManager.setSignalLevelInPercent(0.9f);
525     assertThat(WifiManager.calculateSignalLevel(0, 5)).isEqualTo(3);
526     assertThat(WifiManager.calculateSignalLevel(2, 5)).isEqualTo(3);
527 
528     ShadowWifiManager.setSignalLevelInPercent(1f);
529     assertThat(WifiManager.calculateSignalLevel(0, 4)).isEqualTo(3);
530     assertThat(WifiManager.calculateSignalLevel(2, 4)).isEqualTo(3);
531 
532     ShadowWifiManager.setSignalLevelInPercent(0);
533     assertThat(WifiManager.calculateSignalLevel(0, 5)).isEqualTo(0);
534     assertThat(WifiManager.calculateSignalLevel(2, 5)).isEqualTo(0);
535   }
536 
537   @Test(expected = IllegalArgumentException.class)
shouldThrowIllegalArgumentExceptionWhenSignalLevelToLow()538   public void shouldThrowIllegalArgumentExceptionWhenSignalLevelToLow() {
539     ShadowWifiManager.setSignalLevelInPercent(-0.01f);
540   }
541 
542   @Test(expected = IllegalArgumentException.class)
shouldThrowIllegalArgumentExceptionWhenSignalLevelToHigh()543   public void shouldThrowIllegalArgumentExceptionWhenSignalLevelToHigh() {
544     ShadowWifiManager.setSignalLevelInPercent(1.01f);
545   }
546 
547   @Test
startScan_shouldNotThrowException()548   public void startScan_shouldNotThrowException() {
549     assertThat(wifiManager.startScan()).isTrue();
550   }
551 
552   @Test
reconnect_shouldNotThrowException()553   public void reconnect_shouldNotThrowException() {
554     assertThat(wifiManager.reconnect()).isFalse();
555   }
556 
557   @Test
reconnect_setsConnectionInfo()558   public void reconnect_setsConnectionInfo() {
559     // GIVEN
560     WifiConfiguration wifiConfiguration = new WifiConfiguration();
561     wifiConfiguration.SSID = "SSID";
562     int netId = wifiManager.addNetwork(wifiConfiguration);
563     wifiManager.enableNetwork(netId, false);
564 
565     // WHEN
566     wifiManager.reconnect();
567 
568     // THEN
569     assertThat(wifiManager.getConnectionInfo().getSSID()).contains("SSID");
570   }
571 
572   @Test
reconnect_shouldEnableDhcp()573   public void reconnect_shouldEnableDhcp() {
574     // GIVEN
575     WifiConfiguration config = new WifiConfiguration();
576     config.SSID = "SSID";
577     int netId = wifiManager.addNetwork(config);
578     wifiManager.enableNetwork(netId, false);
579 
580     // WHEN
581     wifiManager.reconnect();
582 
583     // THEN
584     assertThat(wifiManager.getDhcpInfo()).isNotNull();
585   }
586 
587   @Test
reconnect_updatesConnectivityManager()588   public void reconnect_updatesConnectivityManager() {
589     // GIVEN
590     WifiConfiguration config = new WifiConfiguration();
591     config.SSID = "SSID";
592     int netId = wifiManager.addNetwork(config);
593     wifiManager.enableNetwork(netId, false);
594 
595     // WHEN
596     wifiManager.reconnect();
597 
598     // THEN
599     NetworkInfo networkInfo =
600         ((ConnectivityManager)
601                 getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE))
602             .getActiveNetworkInfo();
603     assertThat(networkInfo.getType()).isEqualTo(ConnectivityManager.TYPE_WIFI);
604     assertThat(networkInfo.isConnected()).isTrue();
605   }
606 
607   @Test
connect_setsNetworkId_shouldHasNetworkId()608   public void connect_setsNetworkId_shouldHasNetworkId() {
609     // WHEN
610     wifiManager.connect(123, null);
611 
612     // THEN
613     assertThat(wifiManager.getConnectionInfo().getNetworkId()).isEqualTo(123);
614   }
615 
616   @Test
connect_setsConnectionInfo()617   public void connect_setsConnectionInfo() {
618     // GIVEN
619     WifiConfiguration wifiConfiguration = new WifiConfiguration();
620     wifiConfiguration.SSID = "foo";
621 
622     // WHEN
623     wifiManager.connect(wifiConfiguration, null);
624 
625     // THEN
626     assertThat(wifiManager.getConnectionInfo().getSSID()).contains("foo");
627   }
628 
629   @Test
is5GhzBandSupportedAndConfigurable()630   public void is5GhzBandSupportedAndConfigurable() {
631     assertThat(wifiManager.is5GHzBandSupported()).isFalse();
632     shadowOf(wifiManager).setIs5GHzBandSupported(true);
633     assertThat(wifiManager.is5GHzBandSupported()).isTrue();
634   }
635 
636   @Test
637   @Config(minSdk = R)
isStaApConcurrencySupportedAndConfigurable()638   public void isStaApConcurrencySupportedAndConfigurable() {
639     assertThat(wifiManager.isStaApConcurrencySupported()).isFalse();
640     shadowOf(wifiManager).setStaApConcurrencySupported(true);
641     assertThat(wifiManager.isStaApConcurrencySupported()).isTrue();
642   }
643 
644   @Test
645   @Config(minSdk = Q)
isWpa3SaeSupportedAndConfigurable()646   public void isWpa3SaeSupportedAndConfigurable() {
647     assertThat(wifiManager.isWpa3SaeSupported()).isFalse();
648     shadowOf(wifiManager).setWpa3SaeSupported(true);
649     assertThat(wifiManager.isWpa3SaeSupported()).isTrue();
650   }
651 
652   @Test
653   @Config(minSdk = S)
isWpa3SaePublicKeySupportedAndConfigurable()654   public void isWpa3SaePublicKeySupportedAndConfigurable() {
655     assertThat(wifiManager.isWpa3SaePublicKeySupported()).isFalse();
656     shadowOf(wifiManager).setWpa3SaePublicKeySupported(true);
657     assertThat(wifiManager.isWpa3SaePublicKeySupported()).isTrue();
658   }
659 
660   @Test
661   @Config(minSdk = S)
isWpa3SaeH2eSupportedAndConfigurable()662   public void isWpa3SaeH2eSupportedAndConfigurable() {
663     assertThat(wifiManager.isWpa3SaeH2eSupported()).isFalse();
664     shadowOf(wifiManager).setWpa3SaeH2eSupported(true);
665     assertThat(wifiManager.isWpa3SaeH2eSupported()).isTrue();
666   }
667 
668   @Test
669   @Config(minSdk = Q)
isWpa3SuiteBSupportedAndConfigurable()670   public void isWpa3SuiteBSupportedAndConfigurable() {
671     assertThat(wifiManager.isWpa3SuiteBSupported()).isFalse();
672     shadowOf(wifiManager).setWpa3SuiteBSupported(true);
673     assertThat(wifiManager.isWpa3SuiteBSupported()).isTrue();
674   }
675 
676   @Test
677   @Config(minSdk = Q)
testAddOnWifiUsabilityStatsListener()678   public void testAddOnWifiUsabilityStatsListener() {
679     // GIVEN
680     WifiManager.OnWifiUsabilityStatsListener mockListener =
681         mock(WifiManager.OnWifiUsabilityStatsListener.class);
682     wifiManager.addOnWifiUsabilityStatsListener(directExecutor(), mockListener);
683 
684     // WHEN
685     WifiUsabilityStatsEntryBuilder builder = new WifiUsabilityStatsEntryBuilder();
686     builder
687         .setTimeStampMillis(1234567L)
688         .setRssi(23)
689         .setLinkSpeedMbps(998)
690         .setTotalTxSuccess(1)
691         .setTotalTxRetries(2)
692         .setTotalTxBad(3)
693         .setTotalRxSuccess(4)
694         .setTotalRadioOnTimeMillis(5)
695         .setTotalRadioTxTimeMillis(6)
696         .setTotalRadioRxTimeMillis(7)
697         .setTotalScanTimeMillis(8)
698         .setTotalNanScanTimeMillis(9)
699         .setTotalBackgroundScanTimeMillis(10)
700         .setTotalRoamScanTimeMillis(11)
701         .setTotalPnoScanTimeMillis(12)
702         .setTotalHotspot2ScanTimeMillis(13)
703         .setTotalCcaBusyFreqTimeMillis(14)
704         .setTotalRadioOnFreqTimeMillis(15)
705         .setTotalBeaconRx(16)
706         .setProbeStatusSinceLastUpdate(2)
707         .setProbeElapsedTimeSinceLastUpdateMillis(18)
708         .setProbeMcsRateSinceLastUpdate(19)
709         .setRxLinkSpeedMbps(20)
710         .setCellularDataNetworkType(1)
711         .setCellularSignalStrengthDbm(2)
712         .setCellularSignalStrengthDb(3)
713         .setSameRegisteredCell(false);
714 
715     if (RuntimeEnvironment.getApiLevel() >= S) {
716       builder
717           .setTimeSliceDutyCycleInPercent(10)
718           .setIsCellularDataAvailable(false)
719           .setIsThroughputSufficient(false)
720           .setIsWifiScoringEnabled(false);
721     }
722 
723     shadowOf(wifiManager)
724         .postUsabilityStats(/* seqNum= */ 10, /* isSameBssidAndFreq= */ false, builder);
725     // THEN
726 
727     ArgumentCaptor<WifiUsabilityStatsEntry> usabilityStats =
728         ArgumentCaptor.forClass(WifiUsabilityStatsEntry.class);
729     verify(mockListener).onWifiUsabilityStats(eq(10), eq(false), usabilityStats.capture());
730     assertThat(usabilityStats.getValue().getTimeStampMillis()).isEqualTo(1234567L);
731     assertThat(usabilityStats.getValue().getRssi()).isEqualTo(23);
732     assertThat(usabilityStats.getValue().getLinkSpeedMbps()).isEqualTo(998);
733     assertThat(usabilityStats.getValue().getTotalTxSuccess()).isEqualTo(1);
734     assertThat(usabilityStats.getValue().getTotalTxRetries()).isEqualTo(2);
735     assertThat(usabilityStats.getValue().getTotalTxBad()).isEqualTo(3);
736     assertThat(usabilityStats.getValue().getTotalRxSuccess()).isEqualTo(4);
737     assertThat(usabilityStats.getValue().getTotalRadioOnTimeMillis()).isEqualTo(5);
738     assertThat(usabilityStats.getValue().getTotalRadioTxTimeMillis()).isEqualTo(6);
739     assertThat(usabilityStats.getValue().getTotalRadioRxTimeMillis()).isEqualTo(7);
740     assertThat(usabilityStats.getValue().getTotalScanTimeMillis()).isEqualTo(8);
741     assertThat(usabilityStats.getValue().getTotalNanScanTimeMillis()).isEqualTo(9);
742     assertThat(usabilityStats.getValue().getTotalBackgroundScanTimeMillis()).isEqualTo(10);
743     assertThat(usabilityStats.getValue().getTotalRoamScanTimeMillis()).isEqualTo(11);
744     assertThat(usabilityStats.getValue().getTotalPnoScanTimeMillis()).isEqualTo(12);
745     assertThat(usabilityStats.getValue().getTotalHotspot2ScanTimeMillis()).isEqualTo(13);
746     assertThat(usabilityStats.getValue().getTotalCcaBusyFreqTimeMillis()).isEqualTo(14);
747     assertThat(usabilityStats.getValue().getTotalRadioOnFreqTimeMillis()).isEqualTo(15);
748     assertThat(usabilityStats.getValue().getTotalBeaconRx()).isEqualTo(16);
749     assertThat(usabilityStats.getValue().getProbeStatusSinceLastUpdate()).isEqualTo(2);
750     assertThat(usabilityStats.getValue().getProbeElapsedTimeSinceLastUpdateMillis()).isEqualTo(18);
751     assertThat(usabilityStats.getValue().getProbeMcsRateSinceLastUpdate()).isEqualTo(19);
752     assertThat(usabilityStats.getValue().getRxLinkSpeedMbps()).isEqualTo(20);
753     assertThat(usabilityStats.getValue().getCellularDataNetworkType()).isEqualTo(1);
754     assertThat(usabilityStats.getValue().getCellularSignalStrengthDbm()).isEqualTo(2);
755     assertThat(usabilityStats.getValue().getCellularSignalStrengthDb()).isEqualTo(3);
756     assertThat(usabilityStats.getValue().isSameRegisteredCell()).isFalse();
757     if (RuntimeEnvironment.getApiLevel() >= S) {
758       assertThat(usabilityStats.getValue().getTimeSliceDutyCycleInPercent()).isEqualTo(10);
759       assertThat(usabilityStats.getValue().isCellularDataAvailable()).isFalse();
760       assertThat(usabilityStats.getValue().isThroughputSufficient()).isFalse();
761       assertThat(usabilityStats.getValue().isWifiScoringEnabled()).isFalse();
762     }
763     verifyNoMoreInteractions(mockListener);
764   }
765 
766   @Test
767   @Config(minSdk = Q)
testRemoveOnWifiUsabilityStatsListener()768   public void testRemoveOnWifiUsabilityStatsListener() {
769     // GIVEN
770     WifiManager.OnWifiUsabilityStatsListener mockListener =
771         mock(WifiManager.OnWifiUsabilityStatsListener.class);
772     wifiManager.addOnWifiUsabilityStatsListener(directExecutor(), mockListener);
773 
774     WifiUsabilityStatsEntryBuilder builder = new WifiUsabilityStatsEntryBuilder();
775     builder
776         .setTimeStampMillis(1234567L)
777         .setRssi(23)
778         .setLinkSpeedMbps(998)
779         .setTotalTxSuccess(0)
780         .setTotalTxRetries(0)
781         .setTotalTxBad(0)
782         .setTotalRxSuccess(0)
783         .setTotalRadioOnTimeMillis(0)
784         .setTotalRadioTxTimeMillis(0)
785         .setTotalRadioRxTimeMillis(0)
786         .setTotalScanTimeMillis(0)
787         .setTotalNanScanTimeMillis(0)
788         .setTotalBackgroundScanTimeMillis(0)
789         .setTotalRoamScanTimeMillis(0)
790         .setTotalPnoScanTimeMillis(0)
791         .setTotalHotspot2ScanTimeMillis(0)
792         .setTotalCcaBusyFreqTimeMillis(0)
793         .setTotalRadioOnFreqTimeMillis(0)
794         .setTotalBeaconRx(0)
795         .setProbeStatusSinceLastUpdate(0)
796         .setProbeElapsedTimeSinceLastUpdateMillis(0)
797         .setProbeMcsRateSinceLastUpdate(0)
798         .setRxLinkSpeedMbps(0)
799         .setCellularDataNetworkType(0)
800         .setCellularSignalStrengthDbm(0)
801         .setCellularSignalStrengthDb(0)
802         .setSameRegisteredCell(false);
803 
804     // WHEN
805     wifiManager.removeOnWifiUsabilityStatsListener(mockListener);
806     shadowOf(wifiManager)
807         .postUsabilityStats(/* seqNum= */ 10, /* isSameBssidAndFreq= */ true, builder);
808 
809     // THEN
810     verifyNoMoreInteractions(mockListener);
811   }
812 
813   @Test
814   @Config(minSdk = R)
testSetClearWifiConnectedNetworkScorer()815   public void testSetClearWifiConnectedNetworkScorer() {
816     // GIVEN
817     WifiManager.WifiConnectedNetworkScorer mockScorer =
818         mock(WifiManager.WifiConnectedNetworkScorer.class);
819     // WHEN
820     wifiManager.setWifiConnectedNetworkScorer(directExecutor(), mockScorer);
821     assertThat(shadowOf(wifiManager).isWifiConnectedNetworkScorerEnabled()).isTrue();
822     wifiManager.clearWifiConnectedNetworkScorer();
823 
824     // THEN
825     assertThat(shadowOf(wifiManager).isWifiConnectedNetworkScorerEnabled()).isFalse();
826   }
827 
828   @Test
829   @Config(minSdk = Q)
testGetUsabilityScores()830   public void testGetUsabilityScores() {
831     // GIVEN
832     wifiManager.updateWifiUsabilityScore(
833         /* seqNum= */ 23, /* score= */ 50, /* predictionHorizonSec= */ 16);
834     wifiManager.updateWifiUsabilityScore(
835         /* seqNum= */ 24, /* score= */ 40, /* predictionHorizonSec= */ 16);
836 
837     // WHEN
838     List<ShadowWifiManager.WifiUsabilityScore> scores = shadowOf(wifiManager).getUsabilityScores();
839 
840     // THEN
841     assertThat(scores).hasSize(2);
842     assertThat(scores.get(0).seqNum).isEqualTo(23);
843     assertThat(scores.get(0).score).isEqualTo(50);
844     assertThat(scores.get(0).predictionHorizonSec).isEqualTo(16);
845     assertThat(scores.get(1).seqNum).isEqualTo(24);
846     assertThat(scores.get(1).score).isEqualTo(40);
847     assertThat(scores.get(1).predictionHorizonSec).isEqualTo(16);
848   }
849 
850   @Test
851   @Config(minSdk = Q)
testClearUsabilityScores()852   public void testClearUsabilityScores() {
853     // GIVEN
854     wifiManager.updateWifiUsabilityScore(
855         /* seqNum= */ 23, /* score= */ 50, /* predictionHorizonSec= */ 16);
856     wifiManager.updateWifiUsabilityScore(
857         /* seqNum= */ 24, /* score= */ 40, /* predictionHorizonSec= */ 16);
858 
859     // WHEN
860     shadowOf(wifiManager).clearUsabilityScores();
861     List<ShadowWifiManager.WifiUsabilityScore> scores = shadowOf(wifiManager).getUsabilityScores();
862 
863     // THEN
864     assertThat(scores).isEmpty();
865   }
866 
867   @Test
testSetWifiState()868   public void testSetWifiState() {
869     shadowOf(wifiManager).setWifiState(WifiManager.WIFI_STATE_ENABLED);
870     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLED);
871     assertThat(wifiManager.isWifiEnabled()).isTrue();
872 
873     wifiManager.setWifiEnabled(false);
874     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_DISABLED);
875     assertThat(wifiManager.isWifiEnabled()).isFalse();
876 
877     shadowOf(wifiManager).setWifiState(WifiManager.WIFI_STATE_ENABLING);
878     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLING);
879     assertThat(wifiManager.isWifiEnabled()).isFalse();
880 
881     shadowOf(wifiManager).setWifiState(WifiManager.WIFI_STATE_DISABLING);
882     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_DISABLING);
883     assertThat(wifiManager.isWifiEnabled()).isFalse();
884 
885     shadowOf(wifiManager).setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
886     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_UNKNOWN);
887     assertThat(wifiManager.isWifiEnabled()).isFalse();
888 
889     shadowOf(wifiManager).setWifiState(WifiManager.WIFI_STATE_DISABLED);
890     assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_DISABLED);
891     assertThat(wifiManager.isWifiEnabled()).isFalse();
892   }
893 
894   @Test
shouldRecordTheLastApConfiguration()895   public void shouldRecordTheLastApConfiguration() {
896     WifiConfiguration wifiConfiguration = new WifiConfiguration();
897     wifiConfiguration.SSID = "foo";
898     boolean status = shadowOf(wifiManager).setWifiApConfiguration(wifiConfiguration);
899     assertThat(status).isTrue();
900 
901     assertThat(shadowOf(wifiManager).getWifiApConfiguration().SSID).isEqualTo("foo");
902   }
903 
904   @Test
905   @Config(minSdk = R)
shouldRecordTheLastSoftApConfiguration()906   public void shouldRecordTheLastSoftApConfiguration() {
907     SoftApConfiguration softApConfig =
908         new SoftApConfiguration.Builder()
909             .setSsid("foo")
910             .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN)
911             .build();
912 
913     boolean status = wifiManager.setSoftApConfiguration(softApConfig);
914     assertThat(status).isTrue();
915 
916     assertThat(shadowOf(wifiManager).getSoftApConfiguration().getSsid()).isEqualTo("foo");
917   }
918 
919   @Test
920   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_nullCallback_throwsIllegalArgumentException()921   public void setExternalPnoScanRequest_nullCallback_throwsIllegalArgumentException() {
922     assertThrows(
923         IllegalArgumentException.class,
924         () ->
925             wifiManager.setExternalPnoScanRequest(
926                 List.of(WifiSsid.fromBytes(new byte[] {3, 2, 5})),
927                 /* frequencies= */ null,
928                 Executors.newSingleThreadExecutor(),
929                 /* callback= */ null));
930   }
931 
932   @Test
933   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_nullExecutor_throwsIllegalArgumentException()934   public void setExternalPnoScanRequest_nullExecutor_throwsIllegalArgumentException() {
935     assertThrows(
936         IllegalArgumentException.class,
937         () ->
938             wifiManager.setExternalPnoScanRequest(
939                 List.of(WifiSsid.fromBytes(new byte[] {3, 2, 5})),
940                 /* frequencies= */ null,
941                 /* executor= */ null,
942                 new TestPnoScanResultsCallback()));
943   }
944 
945   @Test
946   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_nullSsidList_throwsIllegalStateException()947   public void setExternalPnoScanRequest_nullSsidList_throwsIllegalStateException() {
948     assertThrows(
949         IllegalStateException.class,
950         () ->
951             wifiManager.setExternalPnoScanRequest(
952                 /* ssids= */ null,
953                 /* frequencies= */ null,
954                 Executors.newSingleThreadExecutor(),
955                 new TestPnoScanResultsCallback()));
956   }
957 
958   @Test
959   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_emptySsidList_throwsIllegalStateException()960   public void setExternalPnoScanRequest_emptySsidList_throwsIllegalStateException() {
961     assertThrows(
962         IllegalStateException.class,
963         () ->
964             wifiManager.setExternalPnoScanRequest(
965                 /* ssids= */ List.of(),
966                 /* frequencies= */ null,
967                 Executors.newSingleThreadExecutor(),
968                 new TestPnoScanResultsCallback()));
969   }
970 
971   @Test
972   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_moreThan2Ssids_throwsIllegalArgumentException()973   public void setExternalPnoScanRequest_moreThan2Ssids_throwsIllegalArgumentException() {
974     assertThrows(
975         IllegalArgumentException.class,
976         () ->
977             wifiManager.setExternalPnoScanRequest(
978                 List.of(
979                     WifiSsid.fromBytes(new byte[] {1, 2, 3}),
980                     WifiSsid.fromBytes(new byte[] {9, 8, 7, 6}),
981                     WifiSsid.fromBytes(new byte[] {90, 81, 72, 63, 54})),
982                 /* frequencies= */ null,
983                 Executors.newSingleThreadExecutor(),
984                 new TestPnoScanResultsCallback()));
985   }
986 
987   @Test
988   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_moreThan10Frequencies_throwsIllegalArgumentException()989   public void setExternalPnoScanRequest_moreThan10Frequencies_throwsIllegalArgumentException() {
990     assertThrows(
991         IllegalArgumentException.class,
992         () ->
993             wifiManager.setExternalPnoScanRequest(
994                 List.of(
995                     WifiSsid.fromBytes(new byte[] {1, 2, 3}),
996                     WifiSsid.fromBytes(new byte[] {9, 8, 7, 6})),
997                 new int[] {5160, 5180, 5200, 5220, 5240, 5260, 5280, 5300, 5320, 5340, 5360},
998                 Executors.newSingleThreadExecutor(),
999                 new TestPnoScanResultsCallback()));
1000   }
1001 
1002   @Test
1003   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_validRequest_successCallbackInvoked()1004   public void setExternalPnoScanRequest_validRequest_successCallbackInvoked() throws Exception {
1005     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1006 
1007     wifiManager.setExternalPnoScanRequest(
1008         List.of(WifiSsid.fromBytes(new byte[] {1, 2, 3})),
1009         /* frequencies= */ null,
1010         Executors.newSingleThreadExecutor(),
1011         callback);
1012 
1013     assertThat(callback.successfulRegistrations.take()).isNotNull();
1014   }
1015 
1016   @Test
1017   @Config(minSdk = TIRAMISU)
1018   public void
setExternalPnoScanRequest_outstandingRequest_failureCallbackInvokedWithAlreadyRegisteredStatus()1019       setExternalPnoScanRequest_outstandingRequest_failureCallbackInvokedWithAlreadyRegisteredStatus()
1020           throws Exception {
1021     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1022 
1023     wifiManager.setExternalPnoScanRequest(
1024         List.of(WifiSsid.fromBytes(new byte[] {1, 2, 3})),
1025         /* frequencies= */ null,
1026         Executors.newSingleThreadExecutor(),
1027         callback);
1028 
1029     wifiManager.setExternalPnoScanRequest(
1030         List.of(WifiSsid.fromBytes(new byte[] {9, 2, 5})),
1031         new int[] {5280},
1032         Executors.newSingleThreadExecutor(),
1033         callback);
1034 
1035     assertThat(callback.failedRegistrations.take())
1036         .isEqualTo(PnoScanResultsCallback.REGISTER_PNO_CALLBACK_ALREADY_REGISTERED);
1037   }
1038 
1039   @Test
1040   @Config(minSdk = TIRAMISU)
setExternalPnoScanRequest_differentUid_failureCallbackInvokedWithBusyStatus()1041   public void setExternalPnoScanRequest_differentUid_failureCallbackInvokedWithBusyStatus()
1042       throws Exception {
1043     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1044 
1045     wifiManager.setExternalPnoScanRequest(
1046         List.of(WifiSsid.fromBytes(new byte[] {1, 2, 3})),
1047         /* frequencies= */ null,
1048         Executors.newSingleThreadExecutor(),
1049         callback);
1050 
1051     int firstAppUid = ShadowProcess.myUid();
1052     int secondAppUid;
1053     do {
1054       secondAppUid = ShadowProcess.getRandomApplicationUid();
1055     } while (firstAppUid == secondAppUid);
1056     ShadowProcess.setUid(secondAppUid);
1057 
1058     wifiManager.setExternalPnoScanRequest(
1059         List.of(WifiSsid.fromBytes(new byte[] {1, 2, 3})),
1060         /* frequencies= */ null,
1061         Executors.newSingleThreadExecutor(),
1062         callback);
1063 
1064     assertThat(callback.failedRegistrations.take())
1065         .isEqualTo(PnoScanResultsCallback.REGISTER_PNO_CALLBACK_RESOURCE_BUSY);
1066   }
1067 
1068   @Test
1069   @Config(minSdk = TIRAMISU)
clearExternalPnoScanRequest_outstandingRequest_callbackInvokedWithUnregisteredStatus()1070   public void clearExternalPnoScanRequest_outstandingRequest_callbackInvokedWithUnregisteredStatus()
1071       throws Exception {
1072     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1073 
1074     wifiManager.setExternalPnoScanRequest(
1075         List.of(WifiSsid.fromBytes(new byte[] {1, 2, 3})),
1076         /* frequencies= */ null,
1077         Executors.newSingleThreadExecutor(),
1078         callback);
1079     wifiManager.clearExternalPnoScanRequest();
1080 
1081     assertThat(callback.removedRegistrations.take())
1082         .isEqualTo(PnoScanResultsCallback.REMOVE_PNO_CALLBACK_UNREGISTERED);
1083   }
1084 
1085   @Test
1086   @Config(minSdk = TIRAMISU)
clearExternalPnoScanRequest_wrongUid_callbackNotInvoked()1087   public void clearExternalPnoScanRequest_wrongUid_callbackNotInvoked() throws Exception {
1088     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1089     ExecutorService executor = Executors.newSingleThreadExecutor();
1090 
1091     wifiManager.setExternalPnoScanRequest(
1092         List.of(WifiSsid.fromBytes(new byte[] {1, 2, 3})),
1093         /* frequencies= */ null,
1094         executor,
1095         callback);
1096 
1097     int firstAppUid = ShadowProcess.myUid();
1098     int secondAppUid;
1099     do {
1100       secondAppUid = ShadowProcess.getRandomApplicationUid();
1101     } while (firstAppUid == secondAppUid);
1102     ShadowProcess.setUid(secondAppUid);
1103 
1104     wifiManager.clearExternalPnoScanRequest();
1105 
1106     executor.shutdown();
1107 
1108     assertThat(executor.awaitTermination(5, MINUTES)).isTrue();
1109     assertThat(callback.removedRegistrations).isEmpty();
1110   }
1111 
1112   @Test
1113   @Config(minSdk = TIRAMISU)
networksFoundFromPnoScan_matchingSsid_availableCallbackInvoked()1114   public void networksFoundFromPnoScan_matchingSsid_availableCallbackInvoked() throws Exception {
1115     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1116     WifiSsid wifiSsid = WifiSsid.fromBytes(new byte[] {1, 2, 3});
1117     ScanResult scanResult = new ScanResult();
1118     scanResult.setWifiSsid(wifiSsid);
1119 
1120     wifiManager.setExternalPnoScanRequest(
1121         List.of(wifiSsid), /* frequencies= */ null, Executors.newSingleThreadExecutor(), callback);
1122     shadowOf(wifiManager).networksFoundFromPnoScan(List.of(scanResult));
1123 
1124     assertThat(callback.incomingScanResults.take()).containsExactly(scanResult);
1125   }
1126 
1127   @Test
1128   @Config(minSdk = TIRAMISU)
networksFoundFromPnoScan_matchingSsid_removedCallbackInvokedWithDeliveredStatus()1129   public void networksFoundFromPnoScan_matchingSsid_removedCallbackInvokedWithDeliveredStatus()
1130       throws Exception {
1131     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1132     WifiSsid wifiSsid = WifiSsid.fromBytes(new byte[] {1, 2, 3});
1133     ScanResult scanResult = new ScanResult();
1134     scanResult.setWifiSsid(wifiSsid);
1135 
1136     wifiManager.setExternalPnoScanRequest(
1137         List.of(wifiSsid), /* frequencies= */ null, Executors.newSingleThreadExecutor(), callback);
1138     shadowOf(wifiManager).networksFoundFromPnoScan(List.of(scanResult));
1139 
1140     assertThat(callback.removedRegistrations.take())
1141         .isEqualTo(PnoScanResultsCallback.REMOVE_PNO_CALLBACK_RESULTS_DELIVERED);
1142   }
1143 
1144   @Test
1145   @Config(minSdk = TIRAMISU)
networksFoundFromPnoScan_matchingSsid_scanResultsAvailableBroadcastSent()1146   public void networksFoundFromPnoScan_matchingSsid_scanResultsAvailableBroadcastSent() {
1147     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1148     WifiSsid wifiSsid = WifiSsid.fromBytes(new byte[] {1, 2, 3});
1149     ScanResult scanResult = new ScanResult();
1150     scanResult.setWifiSsid(wifiSsid);
1151 
1152     wifiManager.setExternalPnoScanRequest(
1153         List.of(wifiSsid), /* frequencies= */ null, Executors.newSingleThreadExecutor(), callback);
1154     shadowOf(wifiManager).networksFoundFromPnoScan(List.of(scanResult));
1155 
1156     Intent expectedIntent = new Intent(SCAN_RESULTS_AVAILABLE_ACTION);
1157     expectedIntent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, true);
1158     expectedIntent.setPackage(getApplicationContext().getPackageName());
1159 
1160     assertThat(
1161             shadowOf((Application) getApplicationContext()).getBroadcastIntents().stream()
1162                 .anyMatch(expectedIntent::filterEquals))
1163         .isTrue();
1164   }
1165 
1166   @Test
1167   @Config(minSdk = TIRAMISU)
networksFoundFromPnoScan_noMatchingSsid_availableCallbackNotInvoked()1168   public void networksFoundFromPnoScan_noMatchingSsid_availableCallbackNotInvoked()
1169       throws Exception {
1170     TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1171     ExecutorService executor = Executors.newSingleThreadExecutor();
1172     WifiSsid wifiSsid = WifiSsid.fromBytes(new byte[] {1, 2, 3});
1173     WifiSsid otherWifiSsid = WifiSsid.fromBytes(new byte[] {9, 8, 7, 6});
1174     ScanResult scanResult = new ScanResult();
1175     scanResult.setWifiSsid(otherWifiSsid);
1176 
1177     wifiManager.setExternalPnoScanRequest(
1178         List.of(wifiSsid), /* frequencies= */ null, executor, callback);
1179     shadowOf(wifiManager).networksFoundFromPnoScan(List.of(scanResult));
1180 
1181     executor.shutdown();
1182 
1183     assertThat(executor.awaitTermination(5, MINUTES)).isTrue();
1184     assertThat(callback.incomingScanResults).isEmpty();
1185   }
1186 
1187   @Test
1188   @Config(minSdk = U.SDK_INT)
addLocalOnlyConnectionFailureListener_nullExecutor_throwsIllegalArgumentException()1189   public void addLocalOnlyConnectionFailureListener_nullExecutor_throwsIllegalArgumentException() {
1190     assertThrows(
1191         IllegalArgumentException.class,
1192         () ->
1193             wifiManager.addLocalOnlyConnectionFailureListener(
1194                 /* executor= */ null, /* listener= */ (unused1, unused2) -> {}));
1195   }
1196 
1197   @Test
1198   @Config(minSdk = U.SDK_INT)
addLocalOnlyConnectionFailureListener_nullListener_throwsIllegalArgumentException()1199   public void addLocalOnlyConnectionFailureListener_nullListener_throwsIllegalArgumentException() {
1200     assertThrows(
1201         IllegalArgumentException.class,
1202         () ->
1203             wifiManager.addLocalOnlyConnectionFailureListener(
1204                 Executors.newSingleThreadExecutor(), /* listener= */ null));
1205   }
1206 
1207   @Test
1208   @Config(minSdk = U.SDK_INT)
1209   public void
removeLocalOnlyConnectionFailureListener_nullListener_throwsIllegalArgumentException()1210       removeLocalOnlyConnectionFailureListener_nullListener_throwsIllegalArgumentException() {
1211     assertThrows(
1212         IllegalArgumentException.class,
1213         () -> wifiManager.removeLocalOnlyConnectionFailureListener(/* listener= */ null));
1214   }
1215 
1216   @Test
1217   @Config(minSdk = U.SDK_INT)
triggerLocalConnectionFailure_callbackTriggered()1218   public void triggerLocalConnectionFailure_callbackTriggered() throws Exception {
1219     ExecutorService executor = Executors.newSingleThreadExecutor();
1220     TestFailureListener listener = new TestFailureListener();
1221     WifiNetworkSpecifier wifiNetworkSpecifier =
1222         new WifiNetworkSpecifier.Builder()
1223             .setSsid("icanhazinternet")
1224             .setBssid(MacAddress.fromString("01:92:83:74:65:AB"))
1225             .setWpa3Passphrase("r3@l gud pa$$w0rd")
1226             .build();
1227 
1228     wifiManager.addLocalOnlyConnectionFailureListener(executor, listener);
1229     ((ShadowWifiManager) Shadow.extract(wifiManager))
1230         .triggerLocalConnectionFailure(
1231             wifiNetworkSpecifier, WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1232     executor.shutdown();
1233 
1234     IncomingFailure incomingFailure = listener.incomingFailures.take();
1235     assertThat(incomingFailure.wifiNetworkSpecifier).isEqualTo(wifiNetworkSpecifier);
1236     assertThat(incomingFailure.failureReason)
1237         .isEqualTo(WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1238   }
1239 
1240   @Test
1241   @Config(minSdk = U.SDK_INT)
triggerLocalConnectionFailure_multipleCallbacksRegistered_allCallbacksTriggered()1242   public void triggerLocalConnectionFailure_multipleCallbacksRegistered_allCallbacksTriggered()
1243       throws Exception {
1244     ExecutorService executor = Executors.newSingleThreadExecutor();
1245     TestFailureListener listener1 = new TestFailureListener();
1246     TestFailureListener listener2 = new TestFailureListener();
1247     WifiNetworkSpecifier wifiNetworkSpecifier =
1248         new WifiNetworkSpecifier.Builder()
1249             .setSsid("icanhazinternet")
1250             .setBssid(MacAddress.fromString("01:92:83:74:65:AB"))
1251             .setWpa3Passphrase("r3@l gud pa$$w0rd")
1252             .build();
1253 
1254     wifiManager.addLocalOnlyConnectionFailureListener(executor, listener1);
1255     wifiManager.addLocalOnlyConnectionFailureListener(executor, listener2);
1256     ((ShadowWifiManager) Shadow.extract(wifiManager))
1257         .triggerLocalConnectionFailure(
1258             wifiNetworkSpecifier, WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1259     executor.shutdown();
1260 
1261     IncomingFailure incomingFailure = listener1.incomingFailures.take();
1262     assertThat(incomingFailure.wifiNetworkSpecifier).isEqualTo(wifiNetworkSpecifier);
1263     assertThat(incomingFailure.failureReason)
1264         .isEqualTo(WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1265     incomingFailure = listener2.incomingFailures.take();
1266     assertThat(incomingFailure.wifiNetworkSpecifier).isEqualTo(wifiNetworkSpecifier);
1267     assertThat(incomingFailure.failureReason)
1268         .isEqualTo(WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1269   }
1270 
1271   @Test
1272   @Config(minSdk = U.SDK_INT)
1273   public void
triggerLocalConnectionFailure_multipleCallbacksRegisteredOnDifferentExecutors_allCallbacksTriggered()1274       triggerLocalConnectionFailure_multipleCallbacksRegisteredOnDifferentExecutors_allCallbacksTriggered()
1275           throws Exception {
1276     ExecutorService executor1 = Executors.newSingleThreadExecutor();
1277     ExecutorService executor2 = Executors.newSingleThreadExecutor();
1278     TestFailureListener listener1 = new TestFailureListener();
1279     TestFailureListener listener2 = new TestFailureListener();
1280     WifiNetworkSpecifier wifiNetworkSpecifier =
1281         new WifiNetworkSpecifier.Builder()
1282             .setSsid("icanhazinternet")
1283             .setBssid(MacAddress.fromString("01:92:83:74:65:AB"))
1284             .setWpa3Passphrase("r3@l gud pa$$w0rd")
1285             .build();
1286 
1287     wifiManager.addLocalOnlyConnectionFailureListener(executor1, listener1);
1288     wifiManager.addLocalOnlyConnectionFailureListener(executor2, listener2);
1289     ((ShadowWifiManager) Shadow.extract(wifiManager))
1290         .triggerLocalConnectionFailure(
1291             wifiNetworkSpecifier, WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1292     executor1.shutdown();
1293     executor2.shutdown();
1294 
1295     IncomingFailure incomingFailure = listener1.incomingFailures.take();
1296     assertThat(incomingFailure.wifiNetworkSpecifier).isEqualTo(wifiNetworkSpecifier);
1297     assertThat(incomingFailure.failureReason)
1298         .isEqualTo(WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1299     incomingFailure = listener2.incomingFailures.take();
1300     assertThat(incomingFailure.wifiNetworkSpecifier).isEqualTo(wifiNetworkSpecifier);
1301     assertThat(incomingFailure.failureReason)
1302         .isEqualTo(WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1303   }
1304 
1305   @Test
1306   @Config(minSdk = U.SDK_INT)
triggerLocalConnectionFailure_listenerRemovedBeforeTrigger_callbackNotInvoked()1307   public void triggerLocalConnectionFailure_listenerRemovedBeforeTrigger_callbackNotInvoked() {
1308     ExecutorService executor = Executors.newSingleThreadExecutor();
1309     TestFailureListener listener = new TestFailureListener();
1310     WifiNetworkSpecifier wifiNetworkSpecifier =
1311         new WifiNetworkSpecifier.Builder()
1312             .setSsid("icanhazinternet")
1313             .setBssid(MacAddress.fromString("01:92:83:74:65:AB"))
1314             .setWpa3Passphrase("r3@l gud pa$$w0rd")
1315             .build();
1316 
1317     wifiManager.addLocalOnlyConnectionFailureListener(executor, listener);
1318     wifiManager.removeLocalOnlyConnectionFailureListener(listener);
1319     ((ShadowWifiManager) Shadow.extract(wifiManager))
1320         .triggerLocalConnectionFailure(
1321             wifiNetworkSpecifier, WifiManager.STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION);
1322     executor.shutdown();
1323 
1324     assertThat(listener.incomingFailures).isEmpty();
1325   }
1326 
1327   private static final class IncomingFailure {
1328     private final WifiNetworkSpecifier wifiNetworkSpecifier;
1329     private final int failureReason;
1330 
IncomingFailure(WifiNetworkSpecifier wifiNetworkSpecifier, int failureReason)1331     IncomingFailure(WifiNetworkSpecifier wifiNetworkSpecifier, int failureReason) {
1332       this.wifiNetworkSpecifier = wifiNetworkSpecifier;
1333       this.failureReason = failureReason;
1334     }
1335   }
1336 
1337   private static final class TestFailureListener implements LocalOnlyConnectionFailureListener {
1338     private final BlockingQueue<IncomingFailure> incomingFailures = new LinkedBlockingQueue<>();
1339 
1340     @Override
onConnectionFailed(WifiNetworkSpecifier wifiNetworkSpecifier, int i)1341     public void onConnectionFailed(WifiNetworkSpecifier wifiNetworkSpecifier, int i) {
1342       incomingFailures.add(new IncomingFailure(wifiNetworkSpecifier, i));
1343     }
1344   }
1345 
1346   private class TestPnoScanResultsCallback implements PnoScanResultsCallback {
1347     LinkedBlockingQueue<List<ScanResult>> incomingScanResults = new LinkedBlockingQueue<>();
1348     LinkedBlockingQueue<Object> successfulRegistrations = new LinkedBlockingQueue<>();
1349     LinkedBlockingQueue<Integer> failedRegistrations = new LinkedBlockingQueue<>();
1350     LinkedBlockingQueue<Integer> removedRegistrations = new LinkedBlockingQueue<>();
1351 
1352     @Override
onScanResultsAvailable(List<ScanResult> scanResults)1353     public void onScanResultsAvailable(List<ScanResult> scanResults) {
1354       incomingScanResults.add(scanResults);
1355     }
1356 
1357     @Override
onRegisterSuccess()1358     public void onRegisterSuccess() {
1359       successfulRegistrations.add(new Object());
1360     }
1361 
1362     @Override
onRegisterFailed(int reason)1363     public void onRegisterFailed(int reason) {
1364       failedRegistrations.add(reason);
1365     }
1366 
1367     @Override
onRemoved(int reason)1368     public void onRemoved(int reason) {
1369       removedRegistrations.add(reason);
1370     }
1371   }
1372 
setDeviceOwner()1373   private void setDeviceOwner() {
1374     shadowOf(
1375             (DevicePolicyManager)
1376                 getApplicationContext().getSystemService(Context.DEVICE_POLICY_SERVICE))
1377         .setDeviceOwner(new ComponentName(getApplicationContext(), DeviceAdminService.class));
1378   }
1379 }
1380