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