• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.wifi.cts;
18 
19 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
21 import static android.net.wifi.SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
22 import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP;
23 import static android.net.wifi.WifiAvailableChannel.OP_MODE_STA;
24 import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
25 import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP;
26 import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE;
27 import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT;
28 import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
29 
30 import static com.google.common.truth.Truth.assertThat;
31 import static com.google.common.truth.Truth.assertWithMessage;
32 
33 import static org.junit.Assert.assertArrayEquals;
34 import static org.junit.Assert.assertNotEquals;
35 import static org.junit.Assert.assertThrows;
36 
37 import android.annotation.NonNull;
38 import android.app.UiAutomation;
39 import android.app.admin.DevicePolicyManager;
40 import android.app.admin.WifiSsidPolicy;
41 import android.content.BroadcastReceiver;
42 import android.content.Context;
43 import android.content.Intent;
44 import android.content.IntentFilter;
45 import android.content.pm.PackageInfo;
46 import android.content.pm.PackageManager;
47 import android.content.pm.ResolveInfo;
48 import android.net.ConnectivityManager;
49 import android.net.MacAddress;
50 import android.net.Network;
51 import android.net.NetworkCapabilities;
52 import android.net.NetworkInfo;
53 import android.net.NetworkRequest;
54 import android.net.TetheringManager;
55 import android.net.Uri;
56 import android.net.wifi.CoexUnsafeChannel;
57 import android.net.wifi.ScanResult;
58 import android.net.wifi.SoftApCapability;
59 import android.net.wifi.SoftApConfiguration;
60 import android.net.wifi.SoftApInfo;
61 import android.net.wifi.WifiAvailableChannel;
62 import android.net.wifi.WifiClient;
63 import android.net.wifi.WifiConfiguration;
64 import android.net.wifi.WifiEnterpriseConfig;
65 import android.net.wifi.WifiInfo;
66 import android.net.wifi.WifiManager;
67 import android.net.wifi.WifiManager.SubsystemRestartTrackingCallback;
68 import android.net.wifi.WifiManager.WifiLock;
69 import android.net.wifi.WifiNetworkConnectionStatistics;
70 import android.net.wifi.WifiNetworkSuggestion;
71 import android.net.wifi.WifiScanner;
72 import android.net.wifi.WifiSsid;
73 import android.net.wifi.hotspot2.ConfigParser;
74 import android.net.wifi.hotspot2.OsuProvider;
75 import android.net.wifi.hotspot2.PasspointConfiguration;
76 import android.net.wifi.hotspot2.ProvisioningCallback;
77 import android.net.wifi.hotspot2.pps.Credential;
78 import android.net.wifi.hotspot2.pps.HomeSp;
79 import android.os.Build;
80 import android.os.Handler;
81 import android.os.HandlerExecutor;
82 import android.os.HandlerThread;
83 import android.os.Process;
84 import android.os.SystemClock;
85 import android.os.SystemProperties;
86 import android.os.UserHandle;
87 import android.platform.test.annotations.AppModeFull;
88 import android.platform.test.annotations.AsbSecurityTest;
89 import android.provider.Settings;
90 import android.support.test.uiautomator.UiDevice;
91 import android.telephony.TelephonyManager;
92 import android.text.TextUtils;
93 import android.util.ArraySet;
94 import android.util.Log;
95 import android.util.SparseArray;
96 import android.util.SparseIntArray;
97 
98 import androidx.test.filters.SdkSuppress;
99 import androidx.test.platform.app.InstrumentationRegistry;
100 
101 import com.android.compatibility.common.util.ApiLevelUtil;
102 import com.android.compatibility.common.util.ApiTest;
103 import com.android.compatibility.common.util.FeatureUtil;
104 import com.android.compatibility.common.util.PollingCheck;
105 import com.android.compatibility.common.util.PropertyUtil;
106 import com.android.compatibility.common.util.ShellIdentityUtils;
107 import com.android.compatibility.common.util.SystemUtil;
108 import com.android.compatibility.common.util.ThrowingRunnable;
109 import com.android.modules.utils.build.SdkLevel;
110 import com.android.net.module.util.MacAddressUtils;
111 
112 import java.io.BufferedReader;
113 import java.io.IOException;
114 import java.io.InputStream;
115 import java.io.InputStreamReader;
116 import java.lang.reflect.Constructor;
117 import java.net.HttpURLConnection;
118 import java.net.InetAddress;
119 import java.net.URL;
120 import java.nio.charset.StandardCharsets;
121 import java.time.Duration;
122 import java.util.ArrayList;
123 import java.util.Arrays;
124 import java.util.Collections;
125 import java.util.HashMap;
126 import java.util.HashSet;
127 import java.util.List;
128 import java.util.Locale;
129 import java.util.Map;
130 import java.util.Objects;
131 import java.util.Set;
132 import java.util.concurrent.ConcurrentLinkedQueue;
133 import java.util.concurrent.CountDownLatch;
134 import java.util.concurrent.Executor;
135 import java.util.concurrent.Executors;
136 import java.util.concurrent.TimeUnit;
137 import java.util.concurrent.atomic.AtomicBoolean;
138 import java.util.concurrent.atomic.AtomicReference;
139 import java.util.function.BiConsumer;
140 import java.util.function.Consumer;
141 import java.util.stream.Collectors;
142 
143 @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
144 public class WifiManagerTest extends WifiJUnit3TestBase {
145     private static class MySync {
146         int expectedState = STATE_NULL;
147     }
148 
149     private WifiManager mWifiManager;
150     private ConnectivityManager mConnectivityManager;
151     private TetheringManager mTetheringManager;
152     private WifiLock mWifiLock;
153     private static MySync mMySync;
154     private List<ScanResult> mScanResults = null;
155     private NetworkInfo mNetworkInfo =
156             new NetworkInfo(ConnectivityManager.TYPE_WIFI, TelephonyManager.NETWORK_TYPE_UNKNOWN,
157                     "wifi", "unknown");
158     private final Object mLock = new Object();
159     private UiDevice mUiDevice;
160     private boolean mWasVerboseLoggingEnabled;
161     private boolean mWasScanThrottleEnabled;
162     private SoftApConfiguration mOriginalSoftApConfig = null;
163 
164     // Please refer to WifiManager
165     private static final int MIN_RSSI = -100;
166     private static final int MAX_RSSI = -55;
167 
168     private static final int STATE_NULL = 0;
169     private static final int STATE_WIFI_CHANGING = 1;
170     private static final int STATE_WIFI_ENABLED = 2;
171     private static final int STATE_WIFI_DISABLED = 3;
172     private static final int STATE_SCANNING = 4;
173     private static final int STATE_SCAN_DONE = 5;
174 
175     private static final String TAG = "WifiManagerTest";
176     private static final String SSID1 = "\"WifiManagerTest\"";
177     private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode";
178     // A full single scan duration is typically about 6-7 seconds, but
179     // depending on devices it takes more time (9-11 seconds). For a
180     // safety margin, the test waits for 15 seconds.
181     private static final int SCAN_TEST_WAIT_DURATION_MS = 15_000;
182     private static final int TEST_WAIT_DURATION_MS = 10_000;
183     private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000;
184     private static final int WIFI_PNO_CONNECT_TIMEOUT_MILLIS = 90_000;
185     private static final int WAIT_MSEC = 60;
186     private static final int DURATION_SCREEN_TOGGLE = 2000;
187     private static final int DURATION_SETTINGS_TOGGLE = 1_000;
188     private static final int DURATION_SOFTAP_START_MS = 6_000;
189     private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000;
190 
191     private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50;
192 
193     private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac";
194     private static final String MANAGED_PROVISIONING_PACKAGE_NAME
195             = "com.android.managedprovisioning";
196 
197     private static final String TEST_SSID_UNQUOTED = "testSsid1";
198     private static final String TEST_IP_ADDRESS = "192.168.5.5";
199     private static final String TEST_MAC_ADDRESS = "aa:bb:cc:dd:ee:ff";
200     private static final MacAddress TEST_MAC = MacAddress.fromString(TEST_MAC_ADDRESS);
201     private static final String TEST_PASSPHRASE = "passphrase";
202     private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT =
203             "assets/ValidPasspointProfile.base64";
204     private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config";
205     private static final String TEST_PSK_CAP = "[RSN-PSK-CCMP]";
206     private static final String TEST_BSSID = "00:01:02:03:04:05";
207     private static final String TEST_COUNTRY_CODE = "JP";
208     private static final String TEST_DOM_SUBJECT_MATCH = "domSubjectMatch";
209     private static final int TEST_SUB_ID = 2;
210     private static final int EID_VSA = 221; // Copied from ScanResult.InformationElement
211     private static final List<ScanResult.InformationElement> TEST_VENDOR_ELEMENTS =
212             new ArrayList<>(Arrays.asList(
213                     new ScanResult.InformationElement(221, 0, new byte[]{ 1, 2, 3, 4 }),
214                     new ScanResult.InformationElement(
215                             221,
216                             0,
217                             new byte[]{ (byte) 170, (byte) 187, (byte) 204, (byte) 221 })
218             ));
219 
220     private IntentFilter mIntentFilter;
221     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
222         @Override
223         public void onReceive(Context context, Intent intent) {
224             final String action = intent.getAction();
225             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
226 
227                 synchronized (mMySync) {
228                     if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) {
229                         mScanResults = mWifiManager.getScanResults();
230                     } else {
231                         mScanResults = null;
232                     }
233                     mMySync.expectedState = STATE_SCAN_DONE;
234                     mMySync.notifyAll();
235                 }
236             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
237                 int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
238                         WifiManager.WIFI_STATE_UNKNOWN);
239                 synchronized (mMySync) {
240                     if (newState == WifiManager.WIFI_STATE_ENABLED) {
241                         Log.d(TAG, "*** New WiFi state is ENABLED ***");
242                         mMySync.expectedState = STATE_WIFI_ENABLED;
243                         mMySync.notifyAll();
244                     } else if (newState == WifiManager.WIFI_STATE_DISABLED) {
245                         Log.d(TAG, "*** New WiFi state is DISABLED ***");
246                         mMySync.expectedState = STATE_WIFI_DISABLED;
247                         mMySync.notifyAll();
248                     }
249                 }
250             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
251                 synchronized (mMySync) {
252                     mNetworkInfo =
253                             (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
254                     if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED)
255                         mMySync.notifyAll();
256                 }
257             }
258         }
259     };
260     // Initialize with an invalid status value (0)
261     private int mProvisioningStatus = 0;
262     // Initialize with an invalid status value (0)
263     private int mProvisioningFailureStatus = 0;
264     private boolean mProvisioningComplete = false;
265     private ProvisioningCallback mProvisioningCallback = new ProvisioningCallback() {
266         @Override
267         public void onProvisioningFailure(int status) {
268             synchronized (mLock) {
269                 mProvisioningFailureStatus = status;
270                 mLock.notify();
271             }
272         }
273 
274         @Override
275         public void onProvisioningStatus(int status) {
276             synchronized (mLock) {
277                 mProvisioningStatus = status;
278                 mLock.notify();
279             }
280         }
281 
282         @Override
283         public void onProvisioningComplete() {
284             mProvisioningComplete = true;
285         }
286     };
287     private int mSubsystemRestartStatus = 0; // 0: nada, 1: restarting, 2: restarted
288     private SubsystemRestartTrackingCallback mSubsystemRestartTrackingCallback =
289             new SubsystemRestartTrackingCallback() {
290                 @Override
291                 public void onSubsystemRestarting() {
292                     synchronized (mLock) {
293                         mSubsystemRestartStatus = 1;
294                         mLock.notify();
295                     }
296                 }
297 
298                 @Override
299                 public void onSubsystemRestarted() {
300                     synchronized (mLock) {
301                         mSubsystemRestartStatus = 2;
302                         mLock.notify();
303                     }
304                 }
305             };
306     private static final String TEST_SSID = "TEST SSID";
307     private static final String TEST_FRIENDLY_NAME = "Friendly Name";
308     private static final Map<String, String> TEST_FRIENDLY_NAMES =
309             new HashMap<String, String>() {
310                 {
311                     put("en", TEST_FRIENDLY_NAME);
312                     put("kr", TEST_FRIENDLY_NAME + 2);
313                     put("jp", TEST_FRIENDLY_NAME + 3);
314                 }
315             };
316     private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service";
317     private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com");
318     private static final String TEST_NAI = "test.access.com";
319     private static final List<Integer> TEST_METHOD_LIST =
320             Arrays.asList(1 /* METHOD_SOAP_XML_SPP */);
321     private final HandlerThread mHandlerThread = new HandlerThread("WifiManagerTest");
322     protected final Executor mExecutor;
323     {
mHandlerThread.start()324         mHandlerThread.start();
325         mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper()));
326     }
327 
328     @Override
setUp()329     protected void setUp() throws Exception {
330         super.setUp();
331         if (!WifiFeature.isWifiSupported(getContext())) {
332             // skip the test if WiFi is not supported
333             return;
334         }
335         mMySync = new MySync();
336         mIntentFilter = new IntentFilter();
337         mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
338         mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
339         mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
340         mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
341         mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
342         mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
343         mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
344         mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK);
345 
346         mContext.registerReceiver(mReceiver, mIntentFilter);
347         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
348         mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
349         mTetheringManager = getContext().getSystemService(TetheringManager.class);
350         assertNotNull(mWifiManager);
351         assertNotNull(mTetheringManager);
352 
353         // turn on verbose logging for tests
354         mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions(
355                 () -> mWifiManager.isVerboseLoggingEnabled());
356         ShellIdentityUtils.invokeWithShellPermissions(
357                 () -> mWifiManager.setVerboseLoggingEnabled(true));
358         // Disable scan throttling for tests.
359         mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions(
360                 () -> mWifiManager.isScanThrottleEnabled());
361         ShellIdentityUtils.invokeWithShellPermissions(
362                 () -> mWifiManager.setScanThrottleEnabled(false));
363 
364         mWifiLock = mWifiManager.createWifiLock(TAG);
365         mWifiLock.acquire();
366         // enable Wifi
367         if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true);
368         PollingCheck.check("Wifi not enabled", TEST_WAIT_DURATION_MS,
369                 () -> mWifiManager.isWifiEnabled());
370 
371         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
372         turnScreenOnNoDelay();
373 
374         synchronized (mMySync) {
375             mMySync.expectedState = STATE_NULL;
376         }
377 
378         List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
379                 mWifiManager::getConfiguredNetworks);
380         assertFalse("Need at least one saved network", savedNetworks.isEmpty());
381 
382         // Get original config for restore
383         mOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions(
384                 mWifiManager::getSoftApConfiguration);
385     }
386 
387     @Override
tearDown()388     protected void tearDown() throws Exception {
389         if (!WifiFeature.isWifiSupported(getContext())) {
390             // skip the test if WiFi is not supported
391             super.tearDown();
392             return;
393         }
394         if (!mWifiManager.isWifiEnabled())
395             setWifiEnabled(true);
396         mWifiLock.release();
397         mContext.unregisterReceiver(mReceiver);
398         ShellIdentityUtils.invokeWithShellPermissions(
399                 () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled));
400         ShellIdentityUtils.invokeWithShellPermissions(
401                 () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled));
402         // restore original softap config
403         ShellIdentityUtils.invokeWithShellPermissions(
404                 () -> mWifiManager.setSoftApConfiguration(mOriginalSoftApConfig));
405         Thread.sleep(TEST_WAIT_DURATION_MS);
406         super.tearDown();
407     }
408 
setWifiEnabled(boolean enable)409     private void setWifiEnabled(boolean enable) throws Exception {
410         synchronized (mMySync) {
411             if (mWifiManager.isWifiEnabled() != enable) {
412                 // the new state is different, we expect it to change
413                 mMySync.expectedState = STATE_WIFI_CHANGING;
414             } else {
415                 mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
416             }
417             // now trigger the change using shell commands.
418             SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable"));
419             waitForExpectedWifiState(enable);
420         }
421     }
422 
waitForExpectedWifiState(boolean enabled)423     private void waitForExpectedWifiState(boolean enabled) throws InterruptedException {
424         synchronized (mMySync) {
425             long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS;
426             int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
427             while (System.currentTimeMillis() < timeout
428                     && mMySync.expectedState != expected) {
429                 mMySync.wait(WAIT_MSEC);
430             }
431         }
432     }
433 
434     // Get the current scan status from sticky broadcast.
isScanCurrentlyAvailable()435     private boolean isScanCurrentlyAvailable() {
436         IntentFilter intentFilter = new IntentFilter();
437         intentFilter.addAction(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED);
438         Intent intent = mContext.registerReceiver(null, intentFilter);
439         assertNotNull(intent);
440         if (intent.getAction().equals(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED)) {
441             return intent.getBooleanExtra(WifiManager.EXTRA_SCAN_AVAILABLE, false);
442         }
443         return false;
444     }
445 
startScan()446     private void startScan() throws Exception {
447         synchronized (mMySync) {
448             mMySync.expectedState = STATE_SCANNING;
449             mScanResults = null;
450             assertTrue(mWifiManager.startScan());
451             long timeout = System.currentTimeMillis() + SCAN_TEST_WAIT_DURATION_MS;
452             while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANNING)
453                 mMySync.wait(WAIT_MSEC);
454         }
455     }
456 
waitForNetworkInfoState(NetworkInfo.State state, int timeoutMillis)457     private void waitForNetworkInfoState(NetworkInfo.State state, int timeoutMillis)
458             throws Exception {
459         synchronized (mMySync) {
460             if (mNetworkInfo.getState() == state) return;
461             long timeout = System.currentTimeMillis() + timeoutMillis;
462             while (System.currentTimeMillis() < timeout
463                     && mNetworkInfo.getState() != state)
464                 mMySync.wait(WAIT_MSEC);
465             assertEquals(state, mNetworkInfo.getState());
466         }
467     }
468 
waitForConnection(int timeoutMillis)469     private void waitForConnection(int timeoutMillis) throws Exception {
470         waitForNetworkInfoState(NetworkInfo.State.CONNECTED, timeoutMillis);
471     }
472 
waitForConnection()473     private void waitForConnection() throws Exception {
474         waitForNetworkInfoState(NetworkInfo.State.CONNECTED, WIFI_CONNECT_TIMEOUT_MILLIS);
475     }
476 
waitForDisconnection()477     private void waitForDisconnection() throws Exception {
478         waitForNetworkInfoState(NetworkInfo.State.DISCONNECTED, TEST_WAIT_DURATION_MS);
479     }
480 
ensureNotNetworkInfoState(NetworkInfo.State state)481     private void ensureNotNetworkInfoState(NetworkInfo.State state) throws Exception {
482         synchronized (mMySync) {
483             long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS + WAIT_MSEC;
484             while (System.currentTimeMillis() < timeout) {
485                 assertNotEquals(state, mNetworkInfo.getState());
486                 mMySync.wait(WAIT_MSEC);
487             }
488         }
489     }
490 
ensureNotConnected()491     private void ensureNotConnected() throws Exception {
492         ensureNotNetworkInfoState(NetworkInfo.State.CONNECTED);
493     }
494 
ensureNotDisconnected()495     private void ensureNotDisconnected() throws Exception {
496         ensureNotNetworkInfoState(NetworkInfo.State.DISCONNECTED);
497     }
498 
existSSID(String ssid)499     private boolean existSSID(String ssid) {
500         for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) {
501             if (w.SSID.equals(ssid))
502                 return true;
503         }
504         return false;
505     }
506 
findConfiguredNetworks(String SSID, List<WifiConfiguration> networks)507     private int findConfiguredNetworks(String SSID, List<WifiConfiguration> networks) {
508         for (final WifiConfiguration w : networks) {
509             if (w.SSID.equals(SSID))
510                 return networks.indexOf(w);
511         }
512         return -1;
513     }
514 
515     /**
516      * Test creation of WifiManager Lock.
517      */
testWifiManagerLock()518     public void testWifiManagerLock() throws Exception {
519         if (!WifiFeature.isWifiSupported(getContext())) {
520             // skip the test if WiFi is not supported
521             return;
522         }
523         final String TAG = "Test";
524         assertNotNull(mWifiManager.createWifiLock(TAG));
525         assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG));
526     }
527 
528     /**
529      * Test wifi scanning when Wifi is off and location scanning is turned on.
530      */
testWifiManagerScanWhenWifiOffLocationTurnedOn()531     public void testWifiManagerScanWhenWifiOffLocationTurnedOn() throws Exception {
532         if (!WifiFeature.isWifiSupported(getContext())) {
533             // skip the test if WiFi is not supported
534             return;
535         }
536         if (!hasLocationFeature()) {
537             Log.d(TAG, "Skipping test as location is not supported");
538             return;
539         }
540         if (!isLocationEnabled()) {
541             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
542                     + " empty when location is disabled!");
543         }
544         runWithScanning(() -> {
545             setWifiEnabled(false);
546             Thread.sleep(TEST_WAIT_DURATION_MS);
547             startScan();
548             if (mWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) {
549                 // Make sure at least one AP is found.
550                 assertNotNull("mScanResult should not be null!", mScanResults);
551                 assertFalse("empty scan results!", mScanResults.isEmpty());
552             } else {
553                 // Make sure no scan results are available.
554                 assertNull("mScanResult should be null!", mScanResults);
555             }
556             final String TAG = "Test";
557             assertNotNull(mWifiManager.createWifiLock(TAG));
558             assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG));
559         }, true /* run with enabled*/);
560     }
561 
562     /**
563      * Restart WiFi subsystem - verify that privileged call fails.
564      */
565     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testRestartWifiSubsystemShouldFailNoPermission()566     public void testRestartWifiSubsystemShouldFailNoPermission() throws Exception {
567         if (!WifiFeature.isWifiSupported(getContext())) {
568             // skip the test if WiFi is not supported
569             return;
570         }
571         try {
572             mWifiManager.restartWifiSubsystem();
573             fail("The restartWifiSubsystem should not succeed - privileged call");
574         } catch (SecurityException e) {
575             // expected
576         }
577     }
578 
579     /**
580      * Restart WiFi subsystem and verify transition through states.
581      */
582     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testRestartWifiSubsystem()583     public void testRestartWifiSubsystem() throws Exception {
584         if (!WifiFeature.isWifiSupported(getContext())) {
585             // skip the test if WiFi is not supported
586             return;
587         }
588         mSubsystemRestartStatus = 0; // 0: uninitialized
589         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
590         try {
591             uiAutomation.adoptShellPermissionIdentity();
592             mWifiManager.registerSubsystemRestartTrackingCallback(mExecutor,
593                     mSubsystemRestartTrackingCallback);
594             synchronized (mLock) {
595                 mWifiManager.restartWifiSubsystem();
596                 mLock.wait(TEST_WAIT_DURATION_MS);
597             }
598             assertEquals(mSubsystemRestartStatus, 1); // 1: restarting
599             waitForExpectedWifiState(false);
600             assertFalse(mWifiManager.isWifiEnabled());
601             synchronized (mLock) {
602                 mLock.wait(TEST_WAIT_DURATION_MS);
603                 assertEquals(mSubsystemRestartStatus, 2); // 2: restarted
604             }
605             waitForExpectedWifiState(true);
606             assertTrue(mWifiManager.isWifiEnabled());
607         } finally {
608             // cleanup
609             mWifiManager.unregisterSubsystemRestartTrackingCallback(
610                     mSubsystemRestartTrackingCallback);
611             uiAutomation.dropShellPermissionIdentity();
612         }
613     }
614 
615     /**
616      * test point of wifiManager properties:
617      * 1.enable properties
618      * 2.DhcpInfo properties
619      * 3.wifi state
620      * 4.ConnectionInfo
621      */
testWifiManagerProperties()622     public void testWifiManagerProperties() throws Exception {
623         if (!WifiFeature.isWifiSupported(getContext())) {
624             // skip the test if WiFi is not supported
625             return;
626         }
627         setWifiEnabled(true);
628         assertTrue(mWifiManager.isWifiEnabled());
629         assertNotNull(mWifiManager.getDhcpInfo());
630         assertEquals(WifiManager.WIFI_STATE_ENABLED, mWifiManager.getWifiState());
631         mWifiManager.getConnectionInfo();
632         setWifiEnabled(false);
633         assertFalse(mWifiManager.isWifiEnabled());
634     }
635 
636     /**
637      * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with
638      * {@link SystemClock#elapsedRealtime()} on device.<p>
639      * To run this test in cts-tradefed:
640      * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp
641      */
642     @VirtualDeviceNotSupported
testWifiScanTimestamp()643     public void testWifiScanTimestamp() throws Exception {
644         if (!WifiFeature.isWifiSupported(getContext())) {
645             Log.d(TAG, "Skipping test as WiFi is not supported");
646             return;
647         }
648         if (!hasLocationFeature()) {
649             Log.d(TAG, "Skipping test as location is not supported");
650             return;
651         }
652         if (!isLocationEnabled()) {
653             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
654                     + " empty when location is disabled!");
655         }
656         if (!mWifiManager.isWifiEnabled()) {
657             setWifiEnabled(true);
658         }
659         // Make sure the scan timestamps are consistent with the device timestamp within the range
660         // of WIFI_SCAN_TEST_CACHE_DELAY_MILLIS.
661         startScan();
662         // Make sure at least one AP is found.
663         assertTrue("mScanResult should not be null. This may be due to a scan timeout",
664                    mScanResults != null);
665         assertFalse("empty scan results!", mScanResults.isEmpty());
666         long nowMillis = SystemClock.elapsedRealtime();
667         // Keep track of how many APs are fresh in one scan.
668         int numFreshAps = 0;
669         for (ScanResult result : mScanResults) {
670             long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp);
671             if (Math.abs(nowMillis - scanTimeMillis)  < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) {
672                 numFreshAps++;
673             }
674         }
675         // At least half of the APs in the scan should be fresh.
676         int numTotalAps = mScanResults.size();
677         String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: "
678                 + numFreshAps;
679         assertTrue(msg, numFreshAps * 2 >= mScanResults.size());
680     }
681 
testConvertBetweenChannelFrequencyMhz()682     public void testConvertBetweenChannelFrequencyMhz() throws Exception {
683         int[] testFrequency_2G = {2412, 2437, 2462, 2484};
684         int[] testFrequency_5G = {5180, 5220, 5540, 5745};
685         int[] testFrequency_6G = {5955, 6435, 6535, 7115};
686         int[] testFrequency_60G = {58320, 64800};
687         SparseArray<int[]> testData = new SparseArray<>() {{
688             put(ScanResult.WIFI_BAND_24_GHZ, testFrequency_2G);
689             put(ScanResult.WIFI_BAND_5_GHZ, testFrequency_5G);
690             put(ScanResult.WIFI_BAND_6_GHZ, testFrequency_6G);
691             put(ScanResult.WIFI_BAND_60_GHZ, testFrequency_60G);
692         }};
693 
694         for (int i = 0; i < testData.size(); i++) {
695             for (int frequency : testData.valueAt(i)) {
696                 assertEquals(frequency, ScanResult.convertChannelToFrequencyMhzIfSupported(
697                       ScanResult.convertFrequencyMhzToChannelIfSupported(frequency), testData.keyAt(i)));
698             }
699         }
700     }
701 
702     // Return true if location is enabled.
isLocationEnabled()703     private boolean isLocationEnabled() {
704         return Settings.Secure.getInt(getContext().getContentResolver(),
705                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) !=
706                 Settings.Secure.LOCATION_MODE_OFF;
707     }
708 
709     // Returns true if the device has location feature.
hasLocationFeature()710     private boolean hasLocationFeature() {
711         return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION);
712     }
713 
hasAutomotiveFeature()714     private boolean hasAutomotiveFeature() {
715         return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
716     }
717 
hasWifiDirect()718     private boolean hasWifiDirect() {
719         return getContext().getPackageManager().hasSystemFeature(
720                 PackageManager.FEATURE_WIFI_DIRECT);
721     }
722 
hasWifiAware()723     private boolean hasWifiAware() {
724         return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
725     }
726 
testSignal()727     public void testSignal() {
728         if (!WifiFeature.isWifiSupported(getContext())) {
729             // skip the test if WiFi is not supported
730             return;
731         }
732         final int numLevels = 9;
733         int expectLevel = 0;
734         assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels));
735         assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels));
736         expectLevel = 4;
737         assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2,
738                 numLevels));
739         int rssiA = 4;
740         int rssiB = 5;
741         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0);
742         rssiB = 4;
743         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0);
744         rssiA = 5;
745         rssiB = 4;
746         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0);
747     }
748 
749     /**
750      * Test that {@link WifiManager#calculateSignalLevel(int)} returns a value in the range
751      * [0, {@link WifiManager#getMaxSignalLevel()}], and its value is monotonically increasing as
752      * the RSSI increases.
753      */
testCalculateSignalLevel()754     public void testCalculateSignalLevel() {
755         if (!WifiFeature.isWifiSupported(getContext())) {
756             // skip the test if WiFi is not supported
757             return;
758         }
759 
760         int maxSignalLevel = mWifiManager.getMaxSignalLevel();
761 
762         int prevSignalLevel = 0;
763         for (int rssi = -150; rssi <= 50; rssi++) {
764             int signalLevel = mWifiManager.calculateSignalLevel(rssi);
765 
766             // between [0, maxSignalLevel]
767             assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(0);
768             assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtMost(maxSignalLevel);
769 
770             // calculateSignalLevel(rssi) <= calculateSignalLevel(rssi + 1)
771             assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(prevSignalLevel);
772             prevSignalLevel = signalLevel;
773         }
774     }
775 
776     public class TestWifiVerboseLoggingStatusChangedListener implements
777             WifiManager.WifiVerboseLoggingStatusChangedListener {
778         public int numCalls;
779         public boolean status;
780 
781         @Override
onWifiVerboseLoggingStatusChanged(boolean enabled)782         public void onWifiVerboseLoggingStatusChanged(boolean enabled) {
783             numCalls++;
784             status = enabled;
785         }
786     }
787 
788     public class TestSoftApCallback implements WifiManager.SoftApCallback {
789         Object softApLock;
790         int currentState;
791         int currentFailureReason;
792         List<SoftApInfo> apInfoList = new ArrayList<>();
793         SoftApInfo apInfoOnSingleApMode;
794         Map<SoftApInfo, List<WifiClient>> apInfoClients = new HashMap<>();
795         List<WifiClient> currentClientList;
796         SoftApCapability currentSoftApCapability;
797         MacAddress lastBlockedClientMacAddress;
798         int lastBlockedClientReason;
799         boolean onStateChangedCalled = false;
800         boolean onSoftApCapabilityChangedCalled = false;
801         boolean onConnectedClientCalled = false;
802         boolean onConnectedClientChangedWithInfoCalled = false;
803         boolean onBlockedClientConnectingCalled = false;
804         int onSoftapInfoChangedCalledCount = 0;
805         int onSoftapInfoChangedWithListCalledCount = 0;
806 
TestSoftApCallback(Object lock)807         TestSoftApCallback(Object lock) {
808             softApLock = lock;
809         }
810 
getOnStateChangedCalled()811         public boolean getOnStateChangedCalled() {
812             synchronized(softApLock) {
813                 return onStateChangedCalled;
814             }
815         }
816 
getOnSoftapInfoChangedCalledCount()817         public int getOnSoftapInfoChangedCalledCount() {
818             synchronized(softApLock) {
819                 return onSoftapInfoChangedCalledCount;
820             }
821         }
822 
getOnSoftApInfoChangedWithListCalledCount()823         public int getOnSoftApInfoChangedWithListCalledCount() {
824             synchronized(softApLock) {
825                 return onSoftapInfoChangedWithListCalledCount;
826             }
827         }
828 
getOnSoftApCapabilityChangedCalled()829         public boolean getOnSoftApCapabilityChangedCalled() {
830             synchronized(softApLock) {
831                 return onSoftApCapabilityChangedCalled;
832             }
833         }
834 
getOnConnectedClientChangedWithInfoCalled()835         public boolean getOnConnectedClientChangedWithInfoCalled() {
836             synchronized(softApLock) {
837                 return onConnectedClientChangedWithInfoCalled;
838             }
839         }
840 
getOnConnectedClientCalled()841         public boolean getOnConnectedClientCalled() {
842             synchronized(softApLock) {
843                 return onConnectedClientCalled;
844             }
845         }
846 
getOnBlockedClientConnectingCalled()847         public boolean getOnBlockedClientConnectingCalled() {
848             synchronized(softApLock) {
849                 return onBlockedClientConnectingCalled;
850             }
851         }
852 
getCurrentState()853         public int getCurrentState() {
854             synchronized(softApLock) {
855                 return currentState;
856             }
857         }
858 
getCurrentStateFailureReason()859         public int getCurrentStateFailureReason() {
860             synchronized(softApLock) {
861                 return currentFailureReason;
862             }
863         }
864 
getCurrentClientList()865         public List<WifiClient> getCurrentClientList() {
866             synchronized(softApLock) {
867                 return new ArrayList<>(currentClientList);
868             }
869         }
870 
getCurrentSoftApInfo()871         public SoftApInfo getCurrentSoftApInfo() {
872             synchronized(softApLock) {
873                 return apInfoOnSingleApMode;
874             }
875         }
876 
getCurrentSoftApInfoList()877         public List<SoftApInfo> getCurrentSoftApInfoList() {
878             synchronized(softApLock) {
879                 return new ArrayList<>(apInfoList);
880             }
881         }
882 
getCurrentSoftApCapability()883         public SoftApCapability getCurrentSoftApCapability() {
884             synchronized(softApLock) {
885                 return currentSoftApCapability;
886             }
887         }
888 
getLastBlockedClientMacAddress()889         public MacAddress getLastBlockedClientMacAddress() {
890             synchronized(softApLock) {
891                 return lastBlockedClientMacAddress;
892             }
893         }
894 
getLastBlockedClientReason()895         public int getLastBlockedClientReason() {
896             synchronized(softApLock) {
897                 return lastBlockedClientReason;
898             }
899         }
900 
901         @Override
onStateChanged(int state, int failureReason)902         public void onStateChanged(int state, int failureReason) {
903             synchronized(softApLock) {
904                 currentState = state;
905                 currentFailureReason = failureReason;
906                 onStateChangedCalled = true;
907             }
908         }
909 
910         @Override
onConnectedClientsChanged(List<WifiClient> clients)911         public void onConnectedClientsChanged(List<WifiClient> clients) {
912             synchronized(softApLock) {
913                 currentClientList = new ArrayList<>(clients);
914                 onConnectedClientCalled = true;
915             }
916         }
917 
918         @Override
onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients)919         public void onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients) {
920             synchronized(softApLock) {
921                 apInfoClients.put(info, clients);
922                 onConnectedClientChangedWithInfoCalled = true;
923             }
924         }
925 
926         @Override
onInfoChanged(List<SoftApInfo> infoList)927         public void onInfoChanged(List<SoftApInfo> infoList) {
928             synchronized(softApLock) {
929                 apInfoList = new ArrayList<>(infoList);
930                 onSoftapInfoChangedWithListCalledCount++;
931             }
932         }
933 
934         @Override
onInfoChanged(SoftApInfo softApInfo)935         public void onInfoChanged(SoftApInfo softApInfo) {
936             synchronized(softApLock) {
937                 apInfoOnSingleApMode = softApInfo;
938                 onSoftapInfoChangedCalledCount++;
939             }
940         }
941 
942         @Override
onCapabilityChanged(SoftApCapability softApCapability)943         public void onCapabilityChanged(SoftApCapability softApCapability) {
944             synchronized(softApLock) {
945                 currentSoftApCapability = softApCapability;
946                 onSoftApCapabilityChangedCalled = true;
947             }
948         }
949 
950         @Override
onBlockedClientConnecting(WifiClient client, int blockedReason)951         public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
952             synchronized(softApLock) {
953                 lastBlockedClientMacAddress = client.getMacAddress();
954                 lastBlockedClientReason = blockedReason;
955                 onBlockedClientConnectingCalled = true;
956             }
957         }
958     }
959 
960     private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback {
961         Object hotspotLock;
962         WifiManager.LocalOnlyHotspotReservation reservation = null;
963         boolean onStartedCalled = false;
964         boolean onStoppedCalled = false;
965         boolean onFailedCalled = false;
966         int failureReason = -1;
967 
TestLocalOnlyHotspotCallback(Object lock)968         TestLocalOnlyHotspotCallback(Object lock) {
969             hotspotLock = lock;
970         }
971 
972         @Override
onStarted(WifiManager.LocalOnlyHotspotReservation r)973         public void onStarted(WifiManager.LocalOnlyHotspotReservation r) {
974             synchronized (hotspotLock) {
975                 reservation = r;
976                 onStartedCalled = true;
977                 hotspotLock.notify();
978             }
979         }
980 
981         @Override
onStopped()982         public void onStopped() {
983             synchronized (hotspotLock) {
984                 onStoppedCalled = true;
985                 hotspotLock.notify();
986             }
987         }
988 
989         @Override
onFailed(int reason)990         public void onFailed(int reason) {
991             synchronized (hotspotLock) {
992                 onFailedCalled = true;
993                 failureReason = reason;
994                 hotspotLock.notify();
995             }
996         }
997     }
998 
getSupportedSoftApBand(SoftApCapability capability)999     private List<Integer> getSupportedSoftApBand(SoftApCapability capability) {
1000         List<Integer> supportedApBands = new ArrayList<>();
1001         if (mWifiManager.is24GHzBandSupported() &&
1002                 capability.areFeaturesSupported(
1003                         SoftApCapability.SOFTAP_FEATURE_BAND_24G_SUPPORTED)) {
1004             supportedApBands.add(SoftApConfiguration.BAND_2GHZ);
1005         }
1006         if (mWifiManager.is5GHzBandSupported() &&
1007                 capability.areFeaturesSupported(
1008                         SoftApCapability.SOFTAP_FEATURE_BAND_5G_SUPPORTED)) {
1009             supportedApBands.add(SoftApConfiguration.BAND_5GHZ);
1010         }
1011         if (mWifiManager.is6GHzBandSupported() &&
1012                 capability.areFeaturesSupported(
1013                         SoftApCapability.SOFTAP_FEATURE_BAND_6G_SUPPORTED)) {
1014             supportedApBands.add(SoftApConfiguration.BAND_6GHZ);
1015         }
1016         if (mWifiManager.is60GHzBandSupported() &&
1017                 capability.areFeaturesSupported(
1018                         SoftApCapability.SOFTAP_FEATURE_BAND_60G_SUPPORTED)) {
1019             supportedApBands.add(SoftApConfiguration.BAND_60GHZ);
1020         }
1021         return supportedApBands;
1022     }
1023 
startLocalOnlyHotspot()1024     private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() {
1025         // Location mode must be enabled for this test
1026         if (!isLocationEnabled()) {
1027             fail("Please enable location for this test");
1028         }
1029 
1030         TestExecutor executor = new TestExecutor();
1031         TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock);
1032         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1033         List<Integer> supportedSoftApBands = new ArrayList<>();
1034         try {
1035             uiAutomation.adoptShellPermissionIdentity();
1036             verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback);
1037             supportedSoftApBands = getSupportedSoftApBand(
1038                     lohsSoftApCallback.getCurrentSoftApCapability());
1039         } catch (Exception ex) {
1040         } finally {
1041             // clean up
1042             unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback);
1043             uiAutomation.dropShellPermissionIdentity();
1044         }
1045         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
1046         synchronized (mLock) {
1047             try {
1048                 mWifiManager.startLocalOnlyHotspot(callback, null);
1049                 // now wait for callback
1050                 mLock.wait(TEST_WAIT_DURATION_MS);
1051             } catch (InterruptedException e) {
1052             }
1053             // check if we got the callback
1054             assertTrue(callback.onStartedCalled);
1055 
1056             SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
1057             assertNotNull(softApConfig);
1058             int securityType = softApConfig.getSecurityType();
1059             if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN
1060                     || securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
1061                     || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) {
1062                 assertNotNull(softApConfig.toWifiConfiguration());
1063             } else {
1064                 assertNull(softApConfig.toWifiConfiguration());
1065             }
1066             if (!hasAutomotiveFeature()) {
1067                 assertEquals(supportedSoftApBands.size() > 0 ? supportedSoftApBands.get(0)
1068                         : SoftApConfiguration.BAND_2GHZ,
1069                         callback.reservation.getSoftApConfiguration().getBand());
1070             }
1071             assertFalse(callback.onFailedCalled);
1072             assertFalse(callback.onStoppedCalled);
1073         }
1074         return callback;
1075     }
1076 
stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled)1077     private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) {
1078        synchronized (mMySync) {
1079            // we are expecting a new state
1080            mMySync.expectedState = STATE_WIFI_CHANGING;
1081 
1082            // now shut down LocalOnlyHotspot
1083            callback.reservation.close();
1084 
1085            try {
1086                waitForExpectedWifiState(wifiEnabled);
1087            } catch (InterruptedException e) {}
1088         }
1089     }
1090 
1091     /**
1092      * Verify that calls to startLocalOnlyHotspot succeed with proper permissions.
1093      *
1094      * Note: Location mode must be enabled for this test.
1095      */
testStartLocalOnlyHotspotSuccess()1096     public void testStartLocalOnlyHotspotSuccess() throws Exception {
1097         if (!WifiFeature.isWifiSupported(getContext())) {
1098             // skip the test if WiFi is not supported
1099             return;
1100         }
1101         // check that softap mode is supported by the device
1102         if (!mWifiManager.isPortableHotspotSupported()) {
1103             return;
1104         }
1105 
1106         boolean wifiEnabled = mWifiManager.isWifiEnabled();
1107 
1108         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
1109 
1110         // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization.
1111         // TODO: remove this sleep as soon as b/124330089 is fixed.
1112         Log.d(TAG, "Sleeping for 2 seconds");
1113         Thread.sleep(2000);
1114 
1115         stopLocalOnlyHotspot(callback, wifiEnabled);
1116 
1117         // wifi should either stay on, or come back on
1118         assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
1119     }
1120 
1121     /**
1122      * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK.
1123      */
testDeprecatedApis()1124     public void testDeprecatedApis() throws Exception {
1125         if (!WifiFeature.isWifiSupported(getContext())) {
1126             // skip the test if WiFi is not supported
1127             return;
1128         }
1129         setWifiEnabled(true);
1130         waitForConnection(); // ensures that there is at-least 1 saved network on the device.
1131 
1132         WifiConfiguration wifiConfiguration = new WifiConfiguration();
1133         wifiConfiguration.SSID = SSID1;
1134         wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
1135 
1136         assertEquals(INVALID_NETWORK_ID,
1137                 mWifiManager.addNetwork(wifiConfiguration));
1138         assertEquals(INVALID_NETWORK_ID,
1139                 mWifiManager.updateNetwork(wifiConfiguration));
1140         assertFalse(mWifiManager.enableNetwork(0, true));
1141         assertFalse(mWifiManager.disableNetwork(0));
1142         assertFalse(mWifiManager.removeNetwork(0));
1143         assertFalse(mWifiManager.disconnect());
1144         assertFalse(mWifiManager.reconnect());
1145         assertFalse(mWifiManager.reassociate());
1146         assertTrue(mWifiManager.getConfiguredNetworks().isEmpty());
1147 
1148         boolean wifiEnabled = mWifiManager.isWifiEnabled();
1149         // now we should fail to toggle wifi state.
1150         assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled));
1151         Thread.sleep(TEST_WAIT_DURATION_MS);
1152         assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
1153     }
1154 
1155     /**
1156      * Test the WifiManager APIs that return whether a feature is supported.
1157      */
testGetSupportedFeatures()1158     public void testGetSupportedFeatures() {
1159         if (!WifiFeature.isWifiSupported(getContext())) {
1160             // skip the test if WiFi is not supported
1161             return;
1162         }
1163         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
1164             // Skip the test if wifi module version is older than S.
1165             return;
1166         }
1167         mWifiManager.isMakeBeforeBreakWifiSwitchingSupported();
1168         mWifiManager.isStaBridgedApConcurrencySupported();
1169     }
1170 
1171     /**
1172      * Verify non DO apps cannot call removeNonCallerConfiguredNetworks.
1173      */
testRemoveNonCallerConfiguredNetworksNotAllowed()1174     public void testRemoveNonCallerConfiguredNetworksNotAllowed() {
1175         if (!WifiFeature.isWifiSupported(getContext())) {
1176             // skip the test if WiFi is not supported
1177             return;
1178         }
1179         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
1180             // Skip the test if wifi module version is older than S.
1181             return;
1182         }
1183         try {
1184             mWifiManager.removeNonCallerConfiguredNetworks();
1185             fail("Expected security exception for non DO app");
1186         } catch (SecurityException e) {
1187         }
1188     }
1189 
1190     /**
1191      * Verify setting the scan schedule.
1192      */
1193     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetScreenOnScanSchedule()1194     public void testSetScreenOnScanSchedule() {
1195         if (!WifiFeature.isWifiSupported(getContext())) {
1196             // skip the test if WiFi is not supported
1197             return;
1198         }
1199         List<WifiManager.ScreenOnScanSchedule> schedules = new ArrayList<>();
1200         schedules.add(new WifiManager.ScreenOnScanSchedule(Duration.ofSeconds(20),
1201                 WifiScanner.SCAN_TYPE_HIGH_ACCURACY));
1202         schedules.add(new WifiManager.ScreenOnScanSchedule(Duration.ofSeconds(40),
1203                 WifiScanner.SCAN_TYPE_LOW_LATENCY));
1204         assertEquals(20, schedules.get(0).getScanInterval().toSeconds());
1205         assertEquals(40, schedules.get(1).getScanInterval().toSeconds());
1206         assertEquals(WifiScanner.SCAN_TYPE_HIGH_ACCURACY, schedules.get(0).getScanType());
1207         assertEquals(WifiScanner.SCAN_TYPE_LOW_LATENCY, schedules.get(1).getScanType());
1208         ShellIdentityUtils.invokeWithShellPermissions(
1209                 () -> mWifiManager.setScreenOnScanSchedule(schedules));
1210         ShellIdentityUtils.invokeWithShellPermissions(
1211                 () -> mWifiManager.setScreenOnScanSchedule(null));
1212 
1213         // Creating an invalid ScanSchedule should throw an exception
1214         assertThrows(IllegalArgumentException.class, () -> new WifiManager.ScreenOnScanSchedule(
1215                 null, WifiScanner.SCAN_TYPE_HIGH_ACCURACY));
1216     }
1217 
1218     /**
1219      * Verify a normal app cannot set the scan schedule.
1220      */
1221     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetScreenOnScanScheduleNoPermission()1222     public void testSetScreenOnScanScheduleNoPermission() {
1223         if (!WifiFeature.isWifiSupported(getContext())) {
1224             // skip the test if WiFi is not supported
1225             return;
1226         }
1227         assertThrows(SecurityException.class, () -> mWifiManager.setScreenOnScanSchedule(null));
1228     }
1229 
1230     /**
1231      * Test coverage for the constructor of AddNetworkResult.
1232      */
testAddNetworkResultCreation()1233     public void testAddNetworkResultCreation() {
1234         if (!WifiFeature.isWifiSupported(getContext())) {
1235             // skip the test if WiFi is not supported
1236             return;
1237         }
1238         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
1239             // Skip the test if wifi module version is older than S.
1240             return;
1241         }
1242         int statusCode = WifiManager.AddNetworkResult.STATUS_NO_PERMISSION;
1243         int networkId = 5;
1244         WifiManager.AddNetworkResult result = new WifiManager.AddNetworkResult(
1245             statusCode, networkId);
1246         assertEquals("statusCode should match", statusCode, result.statusCode);
1247         assertEquals("networkId should match", networkId, result.networkId);
1248     }
1249 
1250     /**
1251      * Verify {@link WifiManager#setSsidsAllowlist(Set)} can be called with sufficient
1252      * privilege.
1253      */
testGetAndSetSsidsAllowlist()1254     public void testGetAndSetSsidsAllowlist() {
1255         if (!WifiFeature.isWifiSupported(getContext())) {
1256             // skip the test if WiFi is not supported
1257             return;
1258         }
1259         Set<WifiSsid> ssids = new ArraySet<>();
1260         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1261         ShellIdentityUtils.invokeWithShellPermissions(
1262                 () -> mWifiManager.setSsidsAllowlist(ssids));
1263 
1264         ShellIdentityUtils.invokeWithShellPermissions(
1265                 () -> assertEquals("Ssids should match", ssids,
1266                         mWifiManager.getSsidsAllowlist()));
1267 
1268         ShellIdentityUtils.invokeWithShellPermissions(
1269                 () -> mWifiManager.setSsidsAllowlist(Collections.EMPTY_SET));
1270         ShellIdentityUtils.invokeWithShellPermissions(
1271                 () -> assertEquals("Should equal to empty set",
1272                         Collections.EMPTY_SET,
1273                         mWifiManager.getSsidsAllowlist()));
1274 
1275         try {
1276             mWifiManager.setSsidsAllowlist(Collections.EMPTY_SET);
1277             fail("Expected SecurityException when called without permission");
1278         } catch (SecurityException e) {
1279             // expect the exception
1280         }
1281     }
1282 
1283     class TestPnoScanResultsCallback implements WifiManager.PnoScanResultsCallback {
1284         public CountDownLatch latch = new CountDownLatch(1);
1285         private boolean mRegisterSuccess;
1286         private int mRegisterFailedReason = -1;
1287         private int mRemovedReason = -1;
1288         private List<ScanResult> mScanResults;
1289 
1290         @Override
onScanResultsAvailable(List<ScanResult> scanResults)1291         public void onScanResultsAvailable(List<ScanResult> scanResults) {
1292             latch.countDown();
1293             mScanResults = scanResults;
1294         }
1295 
1296         @Override
onRegisterSuccess()1297         public void onRegisterSuccess() {
1298             latch.countDown();
1299             mRegisterSuccess = true;
1300         }
1301 
1302         @Override
onRegisterFailed(int reason)1303         public void onRegisterFailed(int reason) {
1304             latch.countDown();
1305             mRegisterFailedReason = reason;
1306         }
1307 
1308         @Override
onRemoved(int reason)1309         public void onRemoved(int reason) {
1310             latch.countDown();
1311             mRemovedReason = reason;
1312         }
1313 
isRegisterSuccess()1314         public boolean isRegisterSuccess() {
1315             return mRegisterSuccess;
1316         }
1317 
getRemovedReason()1318         public int getRemovedReason() {
1319             return mRemovedReason;
1320         }
1321 
getRegisterFailedReason()1322         public int getRegisterFailedReason() {
1323             return mRegisterFailedReason;
1324         }
1325 
getScanResults()1326         public List<ScanResult> getScanResults() {
1327             return mScanResults;
1328         }
1329     }
1330 
1331     /**
1332      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1333      * WifiManager.PnoScanResultsCallback)} can be called with proper permissions.
1334      */
1335     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetExternalPnoScanRequestSuccess()1336     public void testSetExternalPnoScanRequestSuccess() throws Exception {
1337         if (!WifiFeature.isWifiSupported(getContext())) {
1338             // skip the test if WiFi is not supported
1339             return;
1340         }
1341         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1342         List<WifiSsid> ssids = new ArrayList<>();
1343         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1344         int[] frequencies = new int[] {2412, 5180, 5805};
1345 
1346         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1347         ShellIdentityUtils.invokeWithShellPermissions(
1348                 () -> mWifiManager.setExternalPnoScanRequest(
1349                         ssids, frequencies, Executors.newSingleThreadExecutor(), callback));
1350 
1351         callback.latch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS);
1352         if (mWifiManager.isPreferredNetworkOffloadSupported()) {
1353             assertTrue("Expect register success or failed due to resource busy",
1354                     callback.isRegisterSuccess()
1355                     || callback.getRegisterFailedReason() == WifiManager.PnoScanResultsCallback
1356                             .REGISTER_PNO_CALLBACK_RESOURCE_BUSY);
1357         } else {
1358             assertEquals("Expect register fail due to not supported.",
1359                     WifiManager.PnoScanResultsCallback.REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED,
1360                     callback.getRegisterFailedReason());
1361         }
1362         mWifiManager.clearExternalPnoScanRequest();
1363     }
1364 
1365     /**
1366      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1367      * WifiManager.PnoScanResultsCallback)} can be called with null frequency.
1368      */
1369     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetExternalPnoScanRequestSuccessNullFrequency()1370     public void testSetExternalPnoScanRequestSuccessNullFrequency() throws Exception {
1371         if (!WifiFeature.isWifiSupported(getContext())) {
1372             // skip the test if WiFi is not supported
1373             return;
1374         }
1375         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1376         List<WifiSsid> ssids = new ArrayList<>();
1377         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1378 
1379         ShellIdentityUtils.invokeWithShellPermissions(
1380                 () -> mWifiManager.setExternalPnoScanRequest(
1381                         ssids, null, Executors.newSingleThreadExecutor(), callback));
1382         mWifiManager.clearExternalPnoScanRequest();
1383     }
1384 
1385     /**
1386      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1387      * WifiManager.PnoScanResultsCallback)} throws an Exception if called with too many SSIDs.
1388      */
1389     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetExternalPnoScanRequestTooManySsidsException()1390     public void testSetExternalPnoScanRequestTooManySsidsException() throws Exception {
1391         if (!WifiFeature.isWifiSupported(getContext())) {
1392             // skip the test if WiFi is not supported
1393             return;
1394         }
1395         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1396         List<WifiSsid> ssids = new ArrayList<>();
1397         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1398         ssids.add(WifiSsid.fromBytes("TEST_SSID_2".getBytes(StandardCharsets.UTF_8)));
1399         ssids.add(WifiSsid.fromBytes("TEST_SSID_3".getBytes(StandardCharsets.UTF_8)));
1400 
1401         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1402         assertThrows(IllegalArgumentException.class, () -> {
1403             ShellIdentityUtils.invokeWithShellPermissions(
1404                     () -> mWifiManager.setExternalPnoScanRequest(
1405                             ssids, null, Executors.newSingleThreadExecutor(), callback));
1406         });
1407     }
1408 
1409     /**
1410      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1411      * WifiManager.PnoScanResultsCallback)} throws an Exception if called with too many frequencies.
1412      */
1413     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetExternalPnoScanRequestTooManyFrequenciesException()1414     public void testSetExternalPnoScanRequestTooManyFrequenciesException() throws Exception {
1415         if (!WifiFeature.isWifiSupported(getContext())) {
1416             // skip the test if WiFi is not supported
1417             return;
1418         }
1419         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1420         List<WifiSsid> ssids = new ArrayList<>();
1421         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1422         int[] frequencies = new int[] {2412, 2417, 2422, 2427, 2432, 2437, 2447, 2452, 2457, 2462,
1423                 5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805};
1424 
1425         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1426         assertThrows(IllegalArgumentException.class, () -> {
1427             ShellIdentityUtils.invokeWithShellPermissions(
1428                     () -> mWifiManager.setExternalPnoScanRequest(
1429                             ssids, frequencies, Executors.newSingleThreadExecutor(), callback));
1430         });
1431     }
1432 
1433     /**
1434      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1435      * WifiManager.PnoScanResultsCallback)} cannot be called without permission.
1436      */
1437     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetExternalPnoScanRequestNoPermission()1438     public void testSetExternalPnoScanRequestNoPermission() throws Exception {
1439         if (!WifiFeature.isWifiSupported(getContext())) {
1440             // skip the test if WiFi is not supported
1441             return;
1442         }
1443         TestExecutor executor = new TestExecutor();
1444         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1445         List<WifiSsid> ssids = new ArrayList<>();
1446         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1447 
1448         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1449         assertThrows(SecurityException.class,
1450                 () -> mWifiManager.setExternalPnoScanRequest(ssids, null, executor, callback));
1451     }
1452 
1453     /**
1454      * Verify the invalid and valid usages of {@code WifiManager#getLastCallerInfoForApi}.
1455      */
testGetLastCallerInfoForApi()1456     public void testGetLastCallerInfoForApi() throws Exception {
1457         if (!WifiFeature.isWifiSupported(getContext())) {
1458             // skip the test if WiFi is not supported
1459             return;
1460         }
1461         AtomicReference<String> packageName = new AtomicReference<>();
1462         AtomicBoolean enabled = new AtomicBoolean(false);
1463         BiConsumer<String, Boolean> listener = new BiConsumer<String, Boolean>() {
1464             @Override
1465             public void accept(String caller, Boolean value) {
1466                 synchronized (mLock) {
1467                     packageName.set(caller);
1468                     enabled.set(value);
1469                     mLock.notify();
1470                 }
1471             }
1472         };
1473         // Test invalid inputs trigger IllegalArgumentException
1474         assertThrows("Invalid apiType should trigger exception", IllegalArgumentException.class,
1475                 () -> mWifiManager.getLastCallerInfoForApi(-1, mExecutor, listener));
1476         assertThrows("null executor should trigger exception", IllegalArgumentException.class,
1477                 () -> mWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP, null,
1478                         listener));
1479         assertThrows("null listener should trigger exception", IllegalArgumentException.class,
1480                 () -> mWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP, mExecutor,
1481                         null));
1482 
1483         // Test caller with no permission triggers SecurityException.
1484         assertThrows("No permission should trigger SecurityException", SecurityException.class,
1485                 () -> mWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP,
1486                         mExecutor, listener));
1487 
1488         String expectedPackage = "com.android.shell";
1489         boolean isEnabledBefore = mWifiManager.isWifiEnabled();
1490         // toggle wifi and verify getting last caller
1491         setWifiEnabled(!isEnabledBefore);
1492         ShellIdentityUtils.invokeWithShellPermissions(
1493                 () -> mWifiManager.getLastCallerInfoForApi(WifiManager.API_WIFI_ENABLED, mExecutor,
1494                         listener));
1495         synchronized (mLock) {
1496             mLock.wait(TEST_WAIT_DURATION_MS);
1497         }
1498 
1499         assertEquals("package does not match", expectedPackage, packageName.get());
1500         assertEquals("enabled does not match", !isEnabledBefore, enabled.get());
1501 
1502         // toggle wifi again and verify last caller
1503         packageName.set(null);
1504         setWifiEnabled(isEnabledBefore);
1505         ShellIdentityUtils.invokeWithShellPermissions(
1506                 () -> mWifiManager.getLastCallerInfoForApi(WifiManager.API_WIFI_ENABLED, mExecutor,
1507                         listener));
1508         synchronized (mLock) {
1509             mLock.wait(TEST_WAIT_DURATION_MS);
1510         }
1511         assertEquals("package does not match", expectedPackage, packageName.get());
1512         assertEquals("enabled does not match", isEnabledBefore, enabled.get());
1513     }
1514 
1515     /**
1516      * Verify that {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} throws a
1517      * SecurityException when called by a normal app.
1518      */
testAddNetworkPrivilegedNotAllowedForNormalApps()1519     public void testAddNetworkPrivilegedNotAllowedForNormalApps() {
1520         if (!WifiFeature.isWifiSupported(getContext())) {
1521             // skip the test if WiFi is not supported
1522             return;
1523         }
1524         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
1525             // Skip the test if wifi module version is older than S.
1526             return;
1527         }
1528         try {
1529             WifiConfiguration newOpenNetwork = new WifiConfiguration();
1530             newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\"";
1531             mWifiManager.addNetworkPrivileged(newOpenNetwork);
1532             fail("A normal app should not be able to call this API.");
1533         } catch (SecurityException e) {
1534         }
1535     }
1536 
1537     /**
1538      * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} throws an exception when
1539      * null is the input.
1540      */
testAddNetworkPrivilegedBadInput()1541     public void testAddNetworkPrivilegedBadInput() {
1542         if (!WifiFeature.isWifiSupported(getContext())) {
1543             // skip the test if WiFi is not supported
1544             return;
1545         }
1546         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
1547             // Skip the test if wifi module version is older than S.
1548             return;
1549         }
1550         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1551         try {
1552             uiAutomation.adoptShellPermissionIdentity();
1553             mWifiManager.addNetworkPrivileged(null);
1554             fail("Expected IllegalArgumentException");
1555         } catch (IllegalArgumentException e) {
1556         } finally {
1557             uiAutomation.dropShellPermissionIdentity();
1558         }
1559     }
1560 
1561     /**
1562      * Verify {@link WifiManager#getPrivilegedConnectedNetwork()} returns the currently
1563      * connected WifiConfiguration with randomized MAC address filtered out.
1564      */
testGetPrivilegedConnectedNetworkSuccess()1565     public void testGetPrivilegedConnectedNetworkSuccess() throws Exception {
1566         if (!WifiFeature.isWifiSupported(getContext())) {
1567             // skip the test if WiFi is not supported
1568             return;
1569         }
1570         setWifiEnabled(true);
1571         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1572         try {
1573             uiAutomation.adoptShellPermissionIdentity();
1574             mWifiManager.startScan();
1575             waitForConnection(); // ensures that there is at-least 1 saved network on the device.
1576 
1577             WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
1578             int curNetworkId = wifiInfo.getNetworkId();
1579             assertNotEquals("Should be connected to valid networkId", INVALID_NETWORK_ID,
1580                     curNetworkId);
1581             WifiConfiguration curConfig = mWifiManager.getPrivilegedConnectedNetwork();
1582             assertEquals("NetworkId should match", curNetworkId, curConfig.networkId);
1583             assertEquals("SSID should match", wifiInfo.getSSID(), curConfig.SSID);
1584             assertEquals("Randomized MAC should be filtered out", WifiInfo.DEFAULT_MAC_ADDRESS,
1585                     curConfig.getRandomizedMacAddress().toString());
1586         } finally {
1587             uiAutomation.dropShellPermissionIdentity();
1588         }
1589     }
1590 
1591     /**
1592      * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} works properly when the
1593      * calling app has permissions.
1594      */
testAddNetworkPrivilegedSuccess()1595     public void testAddNetworkPrivilegedSuccess() {
1596         if (!WifiFeature.isWifiSupported(getContext())) {
1597             // skip the test if WiFi is not supported
1598             return;
1599         }
1600         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
1601             // Skip the test if wifi module version is older than S.
1602             return;
1603         }
1604         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1605         WifiManager.AddNetworkResult result = null;
1606         try {
1607             uiAutomation.adoptShellPermissionIdentity();
1608             WifiConfiguration newOpenNetwork = new WifiConfiguration();
1609             newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\"";
1610             result = mWifiManager.addNetworkPrivileged(newOpenNetwork);
1611             assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
1612             assertTrue(result.networkId >= 0);
1613             List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks();
1614             boolean found = false;
1615             for (WifiConfiguration config : configuredNetworks) {
1616                 if (config.networkId == result.networkId
1617                         && config.SSID.equals(newOpenNetwork.SSID)) {
1618                     found = true;
1619                     break;
1620                 }
1621             }
1622             assertTrue("addNetworkPrivileged returns success"
1623                     + "but the network is not found in getConfiguredNetworks", found);
1624 
1625             List<WifiConfiguration> privilegedConfiguredNetworks =
1626                     mWifiManager.getPrivilegedConfiguredNetworks();
1627             found = false;
1628             for (WifiConfiguration config : privilegedConfiguredNetworks) {
1629                 if (config.networkId == result.networkId
1630                         && config.SSID.equals(newOpenNetwork.SSID)) {
1631                     found = true;
1632                     break;
1633                 }
1634             }
1635             assertTrue("addNetworkPrivileged returns success"
1636                     + "but the network is not found in getPrivilegedConfiguredNetworks", found);
1637 
1638             List<WifiConfiguration> callerConfiguredNetworks =
1639                     mWifiManager.getCallerConfiguredNetworks();
1640             found = false;
1641             for (WifiConfiguration config : callerConfiguredNetworks) {
1642                 if (config.networkId == result.networkId
1643                         && config.SSID.equals(newOpenNetwork.SSID)) {
1644                     found = true;
1645                     break;
1646                 }
1647             }
1648             assertTrue("addNetworkPrivileged returns success"
1649                     + "but the network is not found in getCallerConfiguredNetworks", found);
1650         } finally {
1651             if (null != result) {
1652                 mWifiManager.removeNetwork(result.networkId);
1653             }
1654             uiAutomation.dropShellPermissionIdentity();
1655         }
1656     }
1657 
createConfig( String ssid, int type)1658     private WifiConfiguration createConfig(
1659             String ssid, int type) {
1660         WifiConfiguration config = new WifiConfiguration();
1661         config.SSID = "\"" + ssid + "\"";
1662         config.setSecurityParams(type);
1663         // set necessary fields for different types.
1664         switch (type) {
1665             case WifiConfiguration.SECURITY_TYPE_OPEN:
1666             case WifiConfiguration.SECURITY_TYPE_OWE:
1667                 break;
1668             case WifiConfiguration.SECURITY_TYPE_PSK:
1669             case WifiConfiguration.SECURITY_TYPE_SAE:
1670                 config.preSharedKey = "\"1qaz@WSX\"";
1671                 break;
1672             case WifiConfiguration.SECURITY_TYPE_EAP:
1673             case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
1674             case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
1675                 config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
1676                 break;
1677         }
1678         return config;
1679     }
1680 
assertConfigsAreFound( List<WifiConfiguration> expectedConfigs, List<WifiConfiguration> configs)1681     private void assertConfigsAreFound(
1682             List<WifiConfiguration> expectedConfigs,
1683             List<WifiConfiguration> configs) {
1684         for (WifiConfiguration expectedConfig: expectedConfigs) {
1685             boolean found = false;
1686             for (WifiConfiguration config : configs) {
1687                 if (config.networkId == expectedConfig.networkId
1688                         && config.getKey().equals(expectedConfig.getKey())) {
1689                     found = true;
1690                     break;
1691                 }
1692             }
1693             assertTrue("the network " + expectedConfig.getKey() + " is not found", found);
1694         }
1695     }
1696 
1697     /**
1698      * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} works
1699      * with merging types properly when the calling app has permissions.
1700      */
testAddNetworkPrivilegedMergingTypeSuccess()1701     public void testAddNetworkPrivilegedMergingTypeSuccess() {
1702         if (!WifiFeature.isWifiSupported(getContext())) {
1703             // skip the test if WiFi is not supported
1704             return;
1705         }
1706         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
1707             // Skip the test if wifi module version is older than S.
1708             return;
1709         }
1710         List<WifiConfiguration> baseConfigs = new ArrayList<>();
1711         baseConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OPEN));
1712         baseConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_PSK));
1713         baseConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
1714                 WifiConfiguration.SECURITY_TYPE_EAP));
1715         List<WifiConfiguration> upgradeConfigs = new ArrayList<>();
1716         upgradeConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OWE));
1717         upgradeConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_SAE));
1718         upgradeConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
1719                 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
1720         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1721         try {
1722             uiAutomation.adoptShellPermissionIdentity();
1723             final int originalConfiguredNetworksNumber = mWifiManager.getConfiguredNetworks().size();
1724             final int originalPrivilegedConfiguredNetworksNumber =
1725                     mWifiManager.getPrivilegedConfiguredNetworks().size();
1726             final int originalCallerConfiguredNetworksNumber =
1727                 mWifiManager.getCallerConfiguredNetworks().size();
1728             for (WifiConfiguration c: baseConfigs) {
1729                 WifiManager.AddNetworkResult result = mWifiManager.addNetworkPrivileged(c);
1730                 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
1731                 assertTrue(result.networkId >= 0);
1732                 c.networkId = result.networkId;
1733             }
1734             for (WifiConfiguration c: upgradeConfigs) {
1735                 WifiManager.AddNetworkResult result = mWifiManager.addNetworkPrivileged(c);
1736                 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
1737                 assertTrue(result.networkId >= 0);
1738                 c.networkId = result.networkId;
1739             }
1740             // open/owe, psk/sae, and wpa2e/wpa3e should be merged
1741             // so they should have the same network ID.
1742             for (int i = 0; i < baseConfigs.size(); i++) {
1743                 assertEquals(baseConfigs.get(i).networkId, upgradeConfigs.get(i).networkId);
1744             }
1745 
1746             int numAddedConfigs = baseConfigs.size();
1747             List<WifiConfiguration> expectedConfigs = new ArrayList<>(baseConfigs);
1748             if (SdkLevel.isAtLeastS()) {
1749                 // S devices and above will return one additional config per each security type
1750                 // added, so we include the number of both base and upgrade configs.
1751                 numAddedConfigs += upgradeConfigs.size();
1752                 expectedConfigs.addAll(upgradeConfigs);
1753             }
1754             List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks();
1755             assertEquals(originalConfiguredNetworksNumber + numAddedConfigs,
1756                     configuredNetworks.size());
1757             assertConfigsAreFound(expectedConfigs, configuredNetworks);
1758 
1759             List<WifiConfiguration> privilegedConfiguredNetworks =
1760                     mWifiManager.getPrivilegedConfiguredNetworks();
1761             assertEquals(originalPrivilegedConfiguredNetworksNumber + numAddedConfigs,
1762                     privilegedConfiguredNetworks.size());
1763             assertConfigsAreFound(expectedConfigs, privilegedConfiguredNetworks);
1764 
1765             List<WifiConfiguration> callerConfiguredNetworks =
1766                     mWifiManager.getCallerConfiguredNetworks();
1767             assertEquals(originalCallerConfiguredNetworksNumber + numAddedConfigs,
1768                     callerConfiguredNetworks.size());
1769             assertConfigsAreFound(expectedConfigs, callerConfiguredNetworks);
1770 
1771         } finally {
1772             for (WifiConfiguration c: baseConfigs) {
1773                 if (c.networkId >= 0) {
1774                     mWifiManager.removeNetwork(c.networkId);
1775                 }
1776             }
1777             uiAutomation.dropShellPermissionIdentity();
1778         }
1779     }
1780 
1781     /**
1782      * Verify that applications can only have one registered LocalOnlyHotspot request at a time.
1783      *
1784      * Note: Location mode must be enabled for this test.
1785      */
testStartLocalOnlyHotspotSingleRequestByApps()1786     public void testStartLocalOnlyHotspotSingleRequestByApps() throws Exception {
1787         if (!WifiFeature.isWifiSupported(getContext())) {
1788             // skip the test if WiFi is not supported
1789             return;
1790         }
1791         // check that softap mode is supported by the device
1792         if (!mWifiManager.isPortableHotspotSupported()) {
1793             return;
1794         }
1795 
1796         boolean caughtException = false;
1797 
1798         boolean wifiEnabled = mWifiManager.isWifiEnabled();
1799 
1800         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
1801 
1802         // now make a second request - this should fail.
1803         TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLock);
1804         try {
1805             mWifiManager.startLocalOnlyHotspot(callback2, null);
1806         } catch (IllegalStateException e) {
1807             Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice");
1808             caughtException = true;
1809         }
1810         if (!caughtException) {
1811             // second start did not fail, should clean up the hotspot.
1812 
1813             // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization.
1814             // TODO: remove this sleep as soon as b/124330089 is fixed.
1815             Log.d(TAG, "Sleeping for 2 seconds");
1816             Thread.sleep(2000);
1817 
1818             stopLocalOnlyHotspot(callback2, wifiEnabled);
1819         }
1820         assertTrue(caughtException);
1821 
1822         // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization.
1823         // TODO: remove this sleep as soon as b/124330089 is fixed.
1824         Log.d(TAG, "Sleeping for 2 seconds");
1825         Thread.sleep(2000);
1826 
1827         stopLocalOnlyHotspot(callback, wifiEnabled);
1828     }
1829 
1830     private static class TestExecutor implements Executor {
1831         private ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>();
1832 
1833         @Override
execute(Runnable task)1834         public void execute(Runnable task) {
1835             tasks.add(task);
1836         }
1837 
runAll()1838         private void runAll() {
1839             Runnable task = tasks.poll();
1840             while (task != null) {
1841                 task.run();
1842                 task = tasks.poll();
1843             }
1844         }
1845     }
1846 
generateSoftApConfigBuilderWithSsid(String ssid)1847     private SoftApConfiguration.Builder generateSoftApConfigBuilderWithSsid(String ssid) {
1848         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
1849             return new SoftApConfiguration.Builder().setWifiSsid(
1850                     WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8)));
1851         }
1852         return new SoftApConfiguration.Builder().setSsid(ssid);
1853     }
1854 
assertSsidEquals(SoftApConfiguration config, String expectedSsid)1855     private void assertSsidEquals(SoftApConfiguration config, String expectedSsid) {
1856         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
1857             assertEquals(WifiSsid.fromBytes(expectedSsid.getBytes(StandardCharsets.UTF_8)),
1858                     config.getWifiSsid());
1859         } else {
1860             assertEquals(expectedSsid, config.getSsid());
1861         }
1862     }
1863 
unregisterLocalOnlyHotspotSoftApCallback(TestSoftApCallback lohsSoftApCallback)1864     private void unregisterLocalOnlyHotspotSoftApCallback(TestSoftApCallback lohsSoftApCallback) {
1865         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
1866             mWifiManager.unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback);
1867         } else {
1868             mWifiManager.unregisterSoftApCallback(lohsSoftApCallback);
1869         }
1870     }
1871 
1872     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testStartLocalOnlyHotspotWithSupportedBand()1873     public void testStartLocalOnlyHotspotWithSupportedBand() throws Exception {
1874         if (!WifiFeature.isWifiSupported(getContext())) {
1875             // skip the test if WiFi is not supported
1876             return;
1877         }
1878 
1879         // check that softap mode is supported by the device
1880         if (!mWifiManager.isPortableHotspotSupported()) {
1881             return;
1882         }
1883 
1884         TestExecutor executor = new TestExecutor();
1885         TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock);
1886         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1887         setWifiEnabled(false);
1888         Thread.sleep(TEST_WAIT_DURATION_MS);
1889         boolean wifiEnabled = mWifiManager.isWifiEnabled();
1890         try {
1891             uiAutomation.adoptShellPermissionIdentity();
1892             verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback);
1893             SoftApConfiguration.Builder customConfigBuilder =
1894                     generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
1895                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
1896 
1897             SparseIntArray testBandsAndChannels = getAvailableBandAndChannelForTesting(
1898                     lohsSoftApCallback.getCurrentSoftApCapability());
1899 
1900             for (int i = 0; i < testBandsAndChannels.size(); i++) {
1901                 TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
1902                 int testBand = testBandsAndChannels.keyAt(i);
1903                 // WPA2_PSK is not allowed in 6GHz band. So test with WPA3_SAE which is
1904                 // mandatory to support in 6GHz band.
1905                 if (testBand == SoftApConfiguration.BAND_6GHZ) {
1906                     customConfigBuilder.setPassphrase(TEST_PASSPHRASE,
1907                             SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
1908                 }
1909                 customConfigBuilder.setBand(testBand);
1910                 mWifiManager.startLocalOnlyHotspot(customConfigBuilder.build(), executor, callback);
1911                 // now wait for callback
1912                 Thread.sleep(DURATION_SOFTAP_START_MS);
1913 
1914                 // Verify callback is run on the supplied executor
1915                 assertFalse(callback.onStartedCalled);
1916                 executor.runAll();
1917                 assertTrue(callback.onStartedCalled);
1918                 assertNotNull(callback.reservation);
1919                 SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
1920                 assertEquals(
1921                         WifiSsid.fromBytes(TEST_SSID_UNQUOTED.getBytes(StandardCharsets.UTF_8)),
1922                         softApConfig.getWifiSsid());
1923                 assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
1924                 // Automotive mode can force the LOHS to specific bands
1925                 if (!hasAutomotiveFeature()) {
1926                     assertEquals(testBand, softApConfig.getBand());
1927                 }
1928                 if (lohsSoftApCallback.getOnSoftapInfoChangedCalledCount() > 1) {
1929                     assertTrue(lohsSoftApCallback.getCurrentSoftApInfo().getFrequency() > 0);
1930                 }
1931                 stopLocalOnlyHotspot(callback, wifiEnabled);
1932             }
1933         } finally {
1934             // clean up
1935             mWifiManager.unregisterSoftApCallback(lohsSoftApCallback);
1936             uiAutomation.dropShellPermissionIdentity();
1937         }
1938     }
1939 
testStartLocalOnlyHotspotWithConfigBssid()1940     public void testStartLocalOnlyHotspotWithConfigBssid() throws Exception {
1941         if (!WifiFeature.isWifiSupported(getContext())) {
1942             // skip the test if WiFi is not supported
1943             return;
1944         }
1945         // check that softap mode is supported by the device
1946         if (!mWifiManager.isPortableHotspotSupported()) {
1947             return;
1948         }
1949 
1950         TestExecutor executor = new TestExecutor();
1951         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
1952         TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock);
1953         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1954         boolean wifiEnabled = mWifiManager.isWifiEnabled();
1955         try {
1956             uiAutomation.adoptShellPermissionIdentity();
1957             verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback);
1958             SoftApConfiguration.Builder customConfigBuilder =
1959                     generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
1960                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
1961 
1962             boolean isSupportCustomizedMac = lohsSoftApCallback.getCurrentSoftApCapability()
1963                         .areFeaturesSupported(
1964                         SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION)
1965                     && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S);
1966             if (isSupportCustomizedMac) {
1967                 customConfigBuilder.setBssid(TEST_MAC).setMacRandomizationSetting(
1968                             SoftApConfiguration.RANDOMIZATION_NONE);
1969             }
1970             SoftApConfiguration customConfig = customConfigBuilder.build();
1971 
1972             mWifiManager.startLocalOnlyHotspot(customConfig, executor, callback);
1973             // now wait for callback
1974             Thread.sleep(TEST_WAIT_DURATION_MS);
1975 
1976             // Verify callback is run on the supplied executor
1977             assertFalse(callback.onStartedCalled);
1978             executor.runAll();
1979             assertTrue(callback.onStartedCalled);
1980 
1981             assertNotNull(callback.reservation);
1982             SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
1983             assertNotNull(softApConfig);
1984             if (isSupportCustomizedMac) {
1985                 assertEquals(TEST_MAC, softApConfig.getBssid());
1986             }
1987             assertSsidEquals(softApConfig, TEST_SSID_UNQUOTED);
1988             assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
1989         } finally {
1990             // clean up
1991             stopLocalOnlyHotspot(callback, wifiEnabled);
1992             unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback);
1993             uiAutomation.dropShellPermissionIdentity();
1994         }
1995     }
1996 
testStartLocalOnlyHotspotWithNullBssidConfig()1997     public void testStartLocalOnlyHotspotWithNullBssidConfig() throws Exception {
1998         if (!WifiFeature.isWifiSupported(getContext())) {
1999             // skip the test if WiFi is not supported
2000             return;
2001         }
2002         // check that softap mode is supported by the device
2003         if (!mWifiManager.isPortableHotspotSupported()) {
2004             return;
2005         }
2006         SoftApConfiguration customConfig =
2007                 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
2008                 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
2009                 .build();
2010 
2011         TestExecutor executor = new TestExecutor();
2012         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
2013         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2014         boolean wifiEnabled = mWifiManager.isWifiEnabled();
2015         try {
2016             uiAutomation.adoptShellPermissionIdentity();
2017 
2018             mWifiManager.startLocalOnlyHotspot(customConfig, executor, callback);
2019             // now wait for callback
2020             Thread.sleep(TEST_WAIT_DURATION_MS);
2021 
2022             // Verify callback is run on the supplied executor
2023             assertFalse(callback.onStartedCalled);
2024             executor.runAll();
2025             assertTrue(callback.onStartedCalled);
2026 
2027             assertNotNull(callback.reservation);
2028             SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
2029             assertNotNull(softApConfig);
2030             assertSsidEquals(softApConfig, TEST_SSID_UNQUOTED);
2031             assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
2032         } finally {
2033             // clean up
2034             stopLocalOnlyHotspot(callback, wifiEnabled);
2035             uiAutomation.dropShellPermissionIdentity();
2036         }
2037     }
2038 
2039     /**
2040      * Read the content of the given resource file into a String.
2041      *
2042      * @param filename String name of the file
2043      * @return String
2044      * @throws IOException
2045      */
loadResourceFile(String filename)2046     private String loadResourceFile(String filename) throws IOException {
2047         InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
2048         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
2049         StringBuilder builder = new StringBuilder();
2050         String line;
2051         while ((line = reader.readLine()) != null) {
2052             builder.append(line).append("\n");
2053         }
2054         return builder.toString();
2055     }
2056 
2057     /**
2058      * Verify that changing the mac randomization setting of a Passpoint configuration.
2059      */
testMacRandomizationSettingPasspoint()2060     public void testMacRandomizationSettingPasspoint() throws Exception {
2061         if (!WifiFeature.isWifiSupported(getContext())) {
2062             // skip the test if WiFi is not supported
2063             return;
2064         }
2065         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
2066         PasspointConfiguration config =
2067                 ConfigParser.parsePasspointConfig(TYPE_WIFI_CONFIG, configStr.getBytes());
2068         String fqdn = config.getHomeSp().getFqdn();
2069         String uniqueId = config.getUniqueId();
2070         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2071         try {
2072             uiAutomation.adoptShellPermissionIdentity();
2073 
2074             mWifiManager.addOrUpdatePasspointConfiguration(config);
2075             PasspointConfiguration passpointConfig = getTargetPasspointConfiguration(
2076                     mWifiManager.getPasspointConfigurations(), uniqueId);
2077             assertNotNull("The installed passpoint profile is missing", passpointConfig);
2078             assertTrue("Mac randomization should be enabled for passpoint networks by default.",
2079                     passpointConfig.isMacRandomizationEnabled());
2080 
2081             mWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, false);
2082             passpointConfig = getTargetPasspointConfiguration(
2083                     mWifiManager.getPasspointConfigurations(), uniqueId);
2084             assertNotNull("The installed passpoint profile is missing", passpointConfig);
2085             assertFalse("Mac randomization should be disabled by the API call.",
2086                     passpointConfig.isMacRandomizationEnabled());
2087         } finally {
2088             // Clean up
2089             mWifiManager.removePasspointConfiguration(fqdn);
2090             uiAutomation.dropShellPermissionIdentity();
2091         }
2092     }
2093     /**
2094      * Verify that the {@link android.Manifest.permission#NETWORK_STACK} permission is never held by
2095      * any package.
2096      * <p>
2097      * No apps should <em>ever</em> attempt to acquire this permission, since it would give those
2098      * apps extremely broad access to connectivity functionality.
2099      */
testNetworkStackPermission()2100     public void testNetworkStackPermission() {
2101         if (!WifiFeature.isWifiSupported(getContext())) {
2102             // skip the test if WiFi is not supported
2103             return;
2104         }
2105         final PackageManager pm = getContext().getPackageManager();
2106 
2107         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2108                 android.Manifest.permission.NETWORK_STACK
2109         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2110         for (PackageInfo pi : holding) {
2111             fail("The NETWORK_STACK permission must not be held by " + pi.packageName
2112                     + " and must be revoked for security reasons");
2113         }
2114     }
2115 
2116     /**
2117      * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is
2118      * never held by any package.
2119      * <p>
2120      * Only Settings, SysUi, NetworkStack and shell apps should <em>ever</em> attempt to acquire
2121      * this permission, since it would give those apps extremely broad access to connectivity
2122      * functionality.  The permission is intended to be granted to only those apps with direct user
2123      * access and no others.
2124      */
testNetworkSettingsPermission()2125     public void testNetworkSettingsPermission() {
2126         if (!WifiFeature.isWifiSupported(getContext())) {
2127             // skip the test if WiFi is not supported
2128             return;
2129         }
2130         final PackageManager pm = getContext().getPackageManager();
2131 
2132         final ArraySet<String> allowedPackages = new ArraySet();
2133         final ArraySet<Integer> allowedUIDs = new ArraySet();
2134         // explicitly add allowed UIDs
2135         allowedUIDs.add(Process.SYSTEM_UID);
2136         allowedUIDs.add(Process.SHELL_UID);
2137         allowedUIDs.add(Process.PHONE_UID);
2138         allowedUIDs.add(Process.NETWORK_STACK_UID);
2139         allowedUIDs.add(Process.NFC_UID);
2140 
2141         // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using
2142         // this fact to determined allowed package name for sysui. This is a signature permission,
2143         // so allow any package with this permission.
2144         final List<PackageInfo> sysuiPackages = pm.getPackagesHoldingPermissions(new String[] {
2145                 android.Manifest.permission.BIND_QUICK_SETTINGS_TILE
2146         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2147         for (PackageInfo info : sysuiPackages) {
2148             allowedPackages.add(info.packageName);
2149         }
2150 
2151         // the captive portal flow also currently holds the NETWORK_SETTINGS permission
2152         final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
2153         final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
2154         if (ri != null) {
2155             allowedPackages.add(ri.activityInfo.packageName);
2156         }
2157 
2158         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2159                 android.Manifest.permission.NETWORK_SETTINGS
2160         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2161         StringBuilder stringBuilder = new StringBuilder();
2162         for (PackageInfo pi : holding) {
2163             String packageName = pi.packageName;
2164 
2165             // this is an explicitly allowed package
2166             if (allowedPackages.contains(packageName)) continue;
2167 
2168             // now check if the packages are from allowed UIDs
2169             int uid = -1;
2170             try {
2171                 uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM);
2172             } catch (PackageManager.NameNotFoundException e) {
2173                 continue;
2174             }
2175             if (!allowedUIDs.contains(uid)) {
2176                 stringBuilder.append("The NETWORK_SETTINGS permission must not be held by "
2177                     + packageName + ":" + uid + " and must be revoked for security reasons\n");
2178             }
2179         }
2180         if (stringBuilder.length() > 0) {
2181             fail(stringBuilder.toString());
2182         }
2183     }
2184 
2185     /**
2186      * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is
2187      * only held by the device setup wizard application.
2188      * <p>
2189      * Only the SetupWizard app should <em>ever</em> attempt to acquire this
2190      * permission, since it would give those apps extremely broad access to connectivity
2191      * functionality.  The permission is intended to be granted to only the device setup wizard.
2192      */
testNetworkSetupWizardPermission()2193     public void testNetworkSetupWizardPermission() {
2194         if (!WifiFeature.isWifiSupported(getContext())) {
2195             // skip the test if WiFi is not supported
2196             return;
2197         }
2198         final ArraySet<String> allowedPackages = new ArraySet();
2199 
2200         final PackageManager pm = getContext().getPackageManager();
2201 
2202         final Intent intent = new Intent(Intent.ACTION_MAIN);
2203         intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
2204         final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
2205         String validPkg = "";
2206         if (ri != null) {
2207             allowedPackages.add(ri.activityInfo.packageName);
2208             validPkg = ri.activityInfo.packageName;
2209         }
2210 
2211         final Intent preIntent = new Intent("com.android.setupwizard.OEM_PRE_SETUP");
2212         preIntent.addCategory(Intent.CATEGORY_DEFAULT);
2213         final ResolveInfo preRi = pm
2214             .resolveActivity(preIntent, PackageManager.MATCH_DISABLED_COMPONENTS);
2215         String prePackageName = "";
2216         if (null != preRi) {
2217             prePackageName = preRi.activityInfo.packageName;
2218         }
2219 
2220         final Intent postIntent = new Intent("com.android.setupwizard.OEM_POST_SETUP");
2221         postIntent.addCategory(Intent.CATEGORY_DEFAULT);
2222         final ResolveInfo postRi = pm
2223             .resolveActivity(postIntent, PackageManager.MATCH_DISABLED_COMPONENTS);
2224         String postPackageName = "";
2225         if (null != postRi) {
2226             postPackageName = postRi.activityInfo.packageName;
2227         }
2228         if (!TextUtils.isEmpty(prePackageName) && !TextUtils.isEmpty(postPackageName)
2229             && prePackageName.equals(postPackageName)) {
2230             allowedPackages.add(prePackageName);
2231         }
2232 
2233         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[]{
2234             android.Manifest.permission.NETWORK_SETUP_WIZARD
2235         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2236         for (PackageInfo pi : holding) {
2237             if (!allowedPackages.contains(pi.packageName)) {
2238                 fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName
2239                     + " and must be revoked for security reasons [" + validPkg + "]");
2240             }
2241         }
2242     }
2243 
2244     /**
2245      * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission
2246      * is only held by the device managed provisioning application.
2247      * <p>
2248      * Only the ManagedProvisioning app should <em>ever</em> attempt to acquire this
2249      * permission, since it would give those apps extremely broad access to connectivity
2250      * functionality.  The permission is intended to be granted to only the device managed
2251      * provisioning.
2252      */
testNetworkManagedProvisioningPermission()2253     public void testNetworkManagedProvisioningPermission() {
2254         if (!WifiFeature.isWifiSupported(getContext())) {
2255             // skip the test if WiFi is not supported
2256             return;
2257         }
2258         final PackageManager pm = getContext().getPackageManager();
2259 
2260         // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the
2261         // managed provisioning app.
2262         // Ensure that the package exists.
2263         final Intent intent = new Intent(Intent.ACTION_MAIN);
2264         intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME);
2265         final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
2266         String validPkg = "";
2267         if (ri != null) {
2268             validPkg = ri.activityInfo.packageName;
2269         }
2270         String dpmHolderName = null;
2271         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2272             DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class);
2273             if (dpm != null) {
2274                 dpmHolderName = dpm.getDevicePolicyManagementRoleHolderPackage();
2275             }
2276         }
2277 
2278         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2279                 android.Manifest.permission.NETWORK_MANAGED_PROVISIONING
2280         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2281         for (PackageInfo pi : holding) {
2282             if (!Objects.equals(pi.packageName, validPkg)
2283                     && !Objects.equals(pi.packageName, dpmHolderName)) {
2284                 fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by "
2285                         + pi.packageName + " and must be revoked for security reasons ["
2286                         + validPkg + ", " + dpmHolderName + "]");
2287             }
2288         }
2289     }
2290 
2291     /**
2292      * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission
2293      * is held by at most one application.
2294      */
testWifiSetDeviceMobilityStatePermission()2295     public void testWifiSetDeviceMobilityStatePermission() {
2296         if (!WifiFeature.isWifiSupported(getContext())) {
2297             // skip the test if WiFi is not supported
2298             return;
2299         }
2300         final PackageManager pm = getContext().getPackageManager();
2301 
2302         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2303                 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE
2304         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2305 
2306         List<String> uniquePackageNames = holding
2307                 .stream()
2308                 .map(pi -> pi.packageName)
2309                 .distinct()
2310                 .collect(Collectors.toList());
2311 
2312         if (uniquePackageNames.size() > 1) {
2313             fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one "
2314                     + "application, but is held by " + uniquePackageNames.size() + " applications: "
2315                     + String.join(", ", uniquePackageNames));
2316         }
2317     }
2318 
2319     /**
2320      * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission
2321      * is held by at most one application.
2322      */
testNetworkCarrierProvisioningPermission()2323     public void testNetworkCarrierProvisioningPermission() {
2324         if (!WifiFeature.isWifiSupported(getContext())) {
2325             // skip the test if WiFi is not supported
2326             return;
2327         }
2328         final PackageManager pm = getContext().getPackageManager();
2329 
2330         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2331                 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
2332         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2333 
2334         List<String> uniquePackageNames = holding
2335                 .stream()
2336                 .map(pi -> pi.packageName)
2337                 .distinct()
2338                 .collect(Collectors.toList());
2339 
2340         if (uniquePackageNames.size() > 2) {
2341             fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two "
2342                     + "applications, but is held by " + uniquePackageNames.size() + " applications: "
2343                     + String.join(", ", uniquePackageNames));
2344         }
2345     }
2346 
2347     /**
2348      * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE}
2349      * permission is held by at most one application.
2350      */
testUpdateWifiUsabilityStatsScorePermission()2351     public void testUpdateWifiUsabilityStatsScorePermission() {
2352         if (!WifiFeature.isWifiSupported(getContext())) {
2353             // skip the test if WiFi is not supported
2354             return;
2355         }
2356         final PackageManager pm = getContext().getPackageManager();
2357 
2358         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2359                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE
2360         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2361 
2362         Set<String> uniqueNonSystemPackageNames = new HashSet<>();
2363         for (PackageInfo pi : holding) {
2364             String packageName = pi.packageName;
2365             // Shell is allowed to hold this permission for testing.
2366             int uid = -1;
2367             try {
2368                 uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM);
2369             } catch (PackageManager.NameNotFoundException e) {
2370                 continue;
2371             }
2372             if (uid == Process.SHELL_UID) continue;
2373 
2374             uniqueNonSystemPackageNames.add(packageName);
2375         }
2376 
2377         if (uniqueNonSystemPackageNames.size() > 1) {
2378             fail("The WIFI_UPDATE_USABILITY_STATS_SCORE permission must not be held by more than "
2379                 + "one application, but is held by " + uniqueNonSystemPackageNames.size()
2380                 + " applications: " + String.join(", ", uniqueNonSystemPackageNames));
2381         }
2382     }
2383 
turnScreenOnNoDelay()2384     private void turnScreenOnNoDelay() throws Exception {
2385         mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
2386         mUiDevice.executeShellCommand("wm dismiss-keyguard");
2387     }
2388 
turnScreenOn()2389     private void turnScreenOn() throws Exception {
2390         turnScreenOnNoDelay();
2391         // Since the screen on/off intent is ordered, they will not be sent right now.
2392         Thread.sleep(DURATION_SCREEN_TOGGLE);
2393     }
2394 
turnScreenOffNoDelay()2395     private void turnScreenOffNoDelay() throws Exception {
2396         mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP");
2397     }
2398 
turnScreenOff()2399     private void turnScreenOff() throws Exception {
2400         turnScreenOffNoDelay();
2401         // Since the screen on/off intent is ordered, they will not be sent right now.
2402         Thread.sleep(DURATION_SCREEN_TOGGLE);
2403     }
2404 
assertWifiScanningIsOn()2405     private void assertWifiScanningIsOn() {
2406         if (!mWifiManager.isScanAlwaysAvailable()) {
2407             fail("Wi-Fi scanning should be on.");
2408         }
2409     }
2410 
runWithScanning(ThrowingRunnable r, boolean isEnabled)2411     private void runWithScanning(ThrowingRunnable r, boolean isEnabled) throws Exception {
2412         boolean scanModeChangedForTest = false;
2413         if (mWifiManager.isScanAlwaysAvailable() != isEnabled) {
2414             ShellIdentityUtils.invokeWithShellPermissions(
2415                     () -> mWifiManager.setScanAlwaysAvailable(isEnabled));
2416             scanModeChangedForTest = true;
2417         }
2418         try {
2419             r.run();
2420         } finally {
2421             if (scanModeChangedForTest) {
2422                 ShellIdentityUtils.invokeWithShellPermissions(
2423                         () -> mWifiManager.setScanAlwaysAvailable(!isEnabled));
2424             }
2425         }
2426     }
2427 
2428     /**
2429      * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled
2430      * but location is on.
2431      * @throws Exception
2432      */
testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled()2433     public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception {
2434         if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) {
2435             // TV and auto do not support the setting options of WIFI scanning and Bluetooth
2436             // scanning
2437             return;
2438         }
2439         if (!WifiFeature.isWifiSupported(getContext())) {
2440             // skip the test if WiFi is not supported
2441             return;
2442         }
2443         if (!hasLocationFeature()) {
2444             // skip the test if location is not supported
2445             return;
2446         }
2447         if (!isLocationEnabled()) {
2448             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
2449                     + " empty when location is disabled!");
2450         }
2451         runWithScanning(() -> {
2452             setWifiEnabled(false);
2453             turnScreenOn();
2454             assertWifiScanningIsOn();
2455             // Toggle screen and verify Wi-Fi scanning is still on.
2456             turnScreenOff();
2457             assertWifiScanningIsOn();
2458             turnScreenOn();
2459             assertWifiScanningIsOn();
2460         }, true /* run with enabled*/);
2461     }
2462 
2463     /**
2464      * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled.
2465      * @throws Exception
2466      */
testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled()2467     public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception {
2468         if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) {
2469             // TV and auto do not support the setting options of WIFI scanning and Bluetooth
2470             // scanning
2471             return;
2472         }
2473         if (!WifiFeature.isWifiSupported(getContext())) {
2474             // skip the test if WiFi is not supported
2475             return;
2476         }
2477         if (!hasLocationFeature()) {
2478             // skip the test if location is not supported
2479             return;
2480         }
2481         if (!isLocationEnabled()) {
2482             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
2483                     + " empty when location is disabled!");
2484         }
2485         runWithScanning(() -> {
2486             setWifiEnabled(true);
2487             turnScreenOn();
2488             assertWifiScanningIsOn();
2489             // Toggle screen and verify Wi-Fi scanning is still on.
2490             turnScreenOff();
2491             assertWifiScanningIsOn();
2492             turnScreenOn();
2493             assertWifiScanningIsOn();
2494         }, true /* run with enabled*/);
2495     }
2496 
2497     /**
2498      * Verify that the platform supports a reasonable number of suggestions per app.
2499      * @throws Exception
2500      */
testMaxNumberOfNetworkSuggestionsPerApp()2501     public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception {
2502         if (!WifiFeature.isWifiSupported(getContext())) {
2503             // skip the test if WiFi is not supported
2504             return;
2505         }
2506         assertTrue(mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp()
2507                 > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP);
2508     }
2509 
verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)2510     private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)
2511             throws Exception {
2512         // Register callback to get SoftApCapability
2513         mWifiManager.registerSoftApCallback(executor, callback);
2514         PollingCheck.check(
2515                 "SoftAp register failed!", 5_000,
2516                 () -> {
2517                     executor.runAll();
2518                     // Verify callback is run on the supplied executor and called
2519                     return callback.getOnStateChangedCalled()
2520                             && callback.getOnSoftapInfoChangedCalledCount() > 0
2521                             && callback.getOnSoftApCapabilityChangedCalled()
2522                             && callback.getOnConnectedClientCalled();
2523                 });
2524     }
2525 
verifyLohsRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)2526     private void verifyLohsRegisterSoftApCallback(TestExecutor executor,
2527             TestSoftApCallback callback) throws Exception {
2528         // Register callback to get SoftApCapability
2529         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2530             mWifiManager.registerLocalOnlyHotspotSoftApCallback(executor, callback);
2531         } else {
2532             mWifiManager.registerSoftApCallback(executor, callback);
2533         }
2534         PollingCheck.check(
2535                 "SoftAp register failed!", 5_000,
2536                 () -> {
2537                     executor.runAll();
2538                     // Verify callback is run on the supplied executor and called
2539                     return callback.getOnStateChangedCalled() &&
2540                             callback.getOnSoftapInfoChangedCalledCount() > 0 &&
2541                             callback.getOnSoftApCapabilityChangedCalled() &&
2542                             callback.getOnConnectedClientCalled();
2543                 });
2544     }
2545 
verifySetGetSoftApConfig(SoftApConfiguration targetConfig)2546     private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) {
2547         mWifiManager.setSoftApConfiguration(targetConfig);
2548         // Bssid set dodesn't support for tethered hotspot
2549         SoftApConfiguration currentConfig = mWifiManager.getSoftApConfiguration();
2550         compareSoftApConfiguration(targetConfig, currentConfig);
2551         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
2552             assertTrue(currentConfig.isUserConfiguration());
2553         }
2554         assertNotNull(currentConfig.getPersistentRandomizedMacAddress());
2555 
2556         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2557             // Verify set/get with the deprecated set/getSsid()
2558             SoftApConfiguration oldSsidConfig = new SoftApConfiguration.Builder(targetConfig)
2559                     .setWifiSsid(null)
2560                     .setSsid(targetConfig.getSsid()).build();
2561             mWifiManager.setSoftApConfiguration(oldSsidConfig);
2562             currentConfig = mWifiManager.getSoftApConfiguration();
2563             compareSoftApConfiguration(oldSsidConfig, currentConfig);
2564         }
2565     }
2566 
compareSoftApConfiguration(SoftApConfiguration currentConfig, SoftApConfiguration testSoftApConfig)2567     private void compareSoftApConfiguration(SoftApConfiguration currentConfig,
2568         SoftApConfiguration testSoftApConfig) {
2569         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2570             assertEquals(currentConfig.getWifiSsid(), testSoftApConfig.getWifiSsid());
2571         }
2572         assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid());
2573         assertEquals(currentConfig.getBssid(), testSoftApConfig.getBssid());
2574         assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType());
2575         assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase());
2576         assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid());
2577         assertEquals(currentConfig.getBand(), testSoftApConfig.getBand());
2578         assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel());
2579         assertEquals(currentConfig.getMaxNumberOfClients(),
2580                 testSoftApConfig.getMaxNumberOfClients());
2581         assertEquals(currentConfig.isAutoShutdownEnabled(),
2582                 testSoftApConfig.isAutoShutdownEnabled());
2583         assertEquals(currentConfig.getShutdownTimeoutMillis(),
2584                 testSoftApConfig.getShutdownTimeoutMillis());
2585         assertEquals(currentConfig.isClientControlByUserEnabled(),
2586                 testSoftApConfig.isClientControlByUserEnabled());
2587         assertEquals(currentConfig.getAllowedClientList(),
2588                 testSoftApConfig.getAllowedClientList());
2589         assertEquals(currentConfig.getBlockedClientList(),
2590                 testSoftApConfig.getBlockedClientList());
2591         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
2592             assertEquals(currentConfig.getMacRandomizationSetting(),
2593                     testSoftApConfig.getMacRandomizationSetting());
2594             assertEquals(currentConfig.getChannels().toString(),
2595                     testSoftApConfig.getChannels().toString());
2596             assertEquals(currentConfig.isBridgedModeOpportunisticShutdownEnabled(),
2597                     testSoftApConfig.isBridgedModeOpportunisticShutdownEnabled());
2598             assertEquals(currentConfig.isIeee80211axEnabled(),
2599                     testSoftApConfig.isIeee80211axEnabled());
2600             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2601                 assertEquals(currentConfig.getBridgedModeOpportunisticShutdownTimeoutMillis(),
2602                         testSoftApConfig.getBridgedModeOpportunisticShutdownTimeoutMillis());
2603                 assertEquals(currentConfig.isIeee80211beEnabled(),
2604                         testSoftApConfig.isIeee80211beEnabled());
2605                 assertEquals(currentConfig.getVendorElements(),
2606                         testSoftApConfig.getVendorElements());
2607                 assertArrayEquals(
2608                         currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ),
2609                         testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ));
2610                 assertArrayEquals(
2611                         currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ),
2612                         testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ));
2613                 assertArrayEquals(
2614                         currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ),
2615                         testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ));
2616                 assertEquals(currentConfig.getMaxChannelBandwidth(),
2617                         testSoftApConfig.getMaxChannelBandwidth());
2618             }
2619         }
2620     }
2621 
turnOffWifiAndTetheredHotspotIfEnabled()2622     private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception {
2623         if (mWifiManager.isWifiEnabled()) {
2624             Log.d(TAG, "Turn off WiFi");
2625             mWifiManager.setWifiEnabled(false);
2626             PollingCheck.check(
2627                 "Wifi turn off failed!", 2_000,
2628                 () -> mWifiManager.isWifiEnabled() == false);
2629         }
2630         if (mWifiManager.isWifiApEnabled()) {
2631             mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
2632             Log.d(TAG, "Turn off tethered Hotspot");
2633             PollingCheck.check(
2634                 "SoftAp turn off failed!", 2_000,
2635                 () -> mWifiManager.isWifiApEnabled() == false);
2636         }
2637     }
2638 
verifyBridgedModeSoftApCallback(TestExecutor executor, TestSoftApCallback callback, boolean shouldFallbackSingleApMode, boolean isEnabled)2639     private void verifyBridgedModeSoftApCallback(TestExecutor executor,
2640             TestSoftApCallback callback, boolean shouldFallbackSingleApMode, boolean isEnabled)
2641             throws Exception {
2642             // Verify state and info callback value as expected
2643             PollingCheck.check(
2644                     "SoftAp state and info on bridged AP mode are mismatch!!!"
2645                     + " shouldFallbackSingleApMode = " + shouldFallbackSingleApMode
2646                     + ", isEnabled = "  + isEnabled, 10_000,
2647                     () -> {
2648                         executor.runAll();
2649                         int expectedState = isEnabled ? WifiManager.WIFI_AP_STATE_ENABLED
2650                                 : WifiManager.WIFI_AP_STATE_DISABLED;
2651                         int expectedInfoSize = isEnabled
2652                                 ? (shouldFallbackSingleApMode ? 1 : 2) : 0;
2653                         return expectedState == callback.getCurrentState()
2654                                 && callback.getCurrentSoftApInfoList().size() == expectedInfoSize;
2655                     });
2656     }
2657 
shouldFallbackToSingleAp(int[] bands, SoftApCapability capability)2658     private boolean shouldFallbackToSingleAp(int[] bands, SoftApCapability capability) {
2659         for (int band : bands) {
2660             if (capability.getSupportedChannelList(band).length == 0) {
2661                 return true;
2662             }
2663         }
2664         return false;
2665     }
2666 
getAvailableBandAndChannelForTesting(SoftApCapability capability)2667     private SparseIntArray getAvailableBandAndChannelForTesting(SoftApCapability capability) {
2668         final int[] bands = {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ,
2669               SoftApConfiguration.BAND_6GHZ, SoftApConfiguration.BAND_60GHZ};
2670         SparseIntArray testBandsAndChannels = new SparseIntArray();
2671         if (!ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
2672             testBandsAndChannels.put(SoftApConfiguration.BAND_2GHZ, 1);
2673             return testBandsAndChannels;
2674         }
2675         for (int band : bands) {
2676             int[] supportedList = capability.getSupportedChannelList(band);
2677             if (supportedList.length != 0) {
2678                 testBandsAndChannels.put(band, supportedList[0]);
2679             }
2680         }
2681         return testBandsAndChannels;
2682     }
2683 
2684     /**
2685      * Skip the test if telephony is not supported and default country code
2686      * is not stored in system property.
2687      */
shouldSkipCountryCodeDependentTest()2688     private boolean shouldSkipCountryCodeDependentTest() {
2689         String countryCode = SystemProperties.get(BOOT_DEFAULT_WIFI_COUNTRY_CODE);
2690         return TextUtils.isEmpty(countryCode) && !WifiFeature.isTelephonySupported(getContext());
2691     }
2692 
2693     /**
2694      * Test SoftApConfiguration#getPersistentRandomizedMacAddress(). There are two test cases in
2695      * this test.
2696      * 1. configure two different SoftApConfigurations (different SSID) and verify that randomized
2697      * MAC address is different.
2698      * 2. configure A then B then A (SSIDs) and verify that the 1st and 3rd MAC addresses are the
2699      * same.
2700      */
testSoftApConfigurationGetPersistentRandomizedMacAddress()2701     public void testSoftApConfigurationGetPersistentRandomizedMacAddress() throws Exception {
2702         SoftApConfiguration currentConfig = ShellIdentityUtils.invokeWithShellPermissions(
2703                 mWifiManager::getSoftApConfiguration);
2704         ShellIdentityUtils.invokeWithShellPermissions(
2705                 () -> mWifiManager.setSoftApConfiguration(new SoftApConfiguration.Builder()
2706                 .setSsid(currentConfig.getSsid() + "test").build()));
2707         SoftApConfiguration changedSsidConfig = ShellIdentityUtils.invokeWithShellPermissions(
2708                 mWifiManager::getSoftApConfiguration);
2709         assertNotEquals(currentConfig.getPersistentRandomizedMacAddress(),
2710                 changedSsidConfig.getPersistentRandomizedMacAddress());
2711 
2712         // set currentConfig
2713         ShellIdentityUtils.invokeWithShellPermissions(
2714                 () -> mWifiManager.setSoftApConfiguration(currentConfig));
2715 
2716         SoftApConfiguration changedSsidBackConfig = ShellIdentityUtils.invokeWithShellPermissions(
2717                 mWifiManager::getSoftApConfiguration);
2718 
2719         assertEquals(currentConfig.getPersistentRandomizedMacAddress(),
2720                 changedSsidBackConfig.getPersistentRandomizedMacAddress());
2721     }
2722 
2723     /**
2724      * Test bridged AP enable succeeful when device supports it.
2725      * Also verify the callback info update correctly.
2726      * @throws Exception
2727      */
2728     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testTetheredBridgedAp()2729     public void testTetheredBridgedAp() throws Exception {
2730         // check that softap bridged mode is supported by the device
2731         if (!mWifiManager.isBridgedApConcurrencySupported()) {
2732             return;
2733         }
2734         runWithScanning(() -> {
2735             UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2736             TestExecutor executor = new TestExecutor();
2737             TestSoftApCallback callback = new TestSoftApCallback(mLock);
2738             try {
2739                 uiAutomation.adoptShellPermissionIdentity();
2740                 // Off/On Wifi to make sure that we get the supported channel
2741                 turnOffWifiAndTetheredHotspotIfEnabled();
2742                 mWifiManager.setWifiEnabled(true);
2743                 PollingCheck.check(
2744                     "Wifi turn on failed!", 2_000,
2745                     () -> mWifiManager.isWifiEnabled() == true);
2746                 turnOffWifiAndTetheredHotspotIfEnabled();
2747                 verifyRegisterSoftApCallback(executor, callback);
2748                 if (!callback.getCurrentSoftApCapability()
2749                         .areFeaturesSupported(SOFTAP_FEATURE_ACS_OFFLOAD)) {
2750                     return;
2751                 }
2752                 int[] testBands = {SoftApConfiguration.BAND_2GHZ,
2753                         SoftApConfiguration.BAND_5GHZ};
2754                 int[] expectedBands = {SoftApConfiguration.BAND_2GHZ,
2755                         SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ};
2756                 // Test bridged SoftApConfiguration set and get (setBands)
2757                 SoftApConfiguration testSoftApConfig =
2758                         generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
2759                         .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
2760                         .setBands(expectedBands)
2761                         .build();
2762 
2763                 boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp(testBands,
2764                         callback.getCurrentSoftApCapability());
2765                 verifySetGetSoftApConfig(testSoftApConfig);
2766 
2767                 // start tethering which used to verify startTetheredHotspot
2768                 mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
2769                     new TetheringManager.StartTetheringCallback() {
2770                         @Override
2771                         public void onTetheringFailed(final int result) {
2772                         }
2773                     });
2774                 verifyBridgedModeSoftApCallback(executor, callback,
2775                         shouldFallbackToSingleAp, true /* enabled */);
2776                 // stop tethering which used to verify stopSoftAp
2777                 mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
2778                 verifyBridgedModeSoftApCallback(executor, callback,
2779                         shouldFallbackToSingleAp, false /* disabled */);
2780             } finally {
2781                 mWifiManager.unregisterSoftApCallback(callback);
2782                 uiAutomation.dropShellPermissionIdentity();
2783             }
2784         }, false /* run with disabled */);
2785     }
2786 
2787     /**
2788      * Test bridged AP with forced channel config enable succeeful when device supports it.
2789      * Also verify the callback info update correctly.
2790      * @throws Exception
2791      */
2792     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testTetheredBridgedApWifiForcedChannel()2793     public void testTetheredBridgedApWifiForcedChannel() throws Exception {
2794         // check that softap bridged mode is supported by the device
2795         if (!mWifiManager.isBridgedApConcurrencySupported()) {
2796             return;
2797         }
2798         runWithScanning(() -> {
2799             UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2800             TestExecutor executor = new TestExecutor();
2801             TestSoftApCallback callback = new TestSoftApCallback(mLock);
2802             try {
2803                 uiAutomation.adoptShellPermissionIdentity();
2804                 // Off/On Wifi to make sure that we get the supported channel
2805                 turnOffWifiAndTetheredHotspotIfEnabled();
2806                 mWifiManager.setWifiEnabled(true);
2807                 PollingCheck.check(
2808                     "Wifi turn on failed!", 2_000,
2809                     () -> mWifiManager.isWifiEnabled() == true);
2810                 turnOffWifiAndTetheredHotspotIfEnabled();
2811                 verifyRegisterSoftApCallback(executor, callback);
2812 
2813                 boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp(
2814                         new int[] {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ},
2815                         callback.getCurrentSoftApCapability());
2816 
2817                 // Test when there are supported channels in both of the bands.
2818                 if (!shouldFallbackToSingleAp) {
2819                     // Test bridged SoftApConfiguration set and get (setChannels)
2820                     SparseIntArray dual_channels = new SparseIntArray(2);
2821                     dual_channels.put(SoftApConfiguration.BAND_2GHZ,
2822                             callback.getCurrentSoftApCapability()
2823                             .getSupportedChannelList(SoftApConfiguration.BAND_2GHZ)[0]);
2824                     dual_channels.put(SoftApConfiguration.BAND_5GHZ,
2825                             callback.getCurrentSoftApCapability()
2826                             .getSupportedChannelList(SoftApConfiguration.BAND_5GHZ)[0]);
2827                     SoftApConfiguration testSoftApConfig =
2828                             generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
2829                             .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
2830                             .setChannels(dual_channels)
2831                             .build();
2832 
2833                     verifySetGetSoftApConfig(testSoftApConfig);
2834 
2835                     // start tethering which used to verify startTetheredHotspot
2836                     mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
2837                         new TetheringManager.StartTetheringCallback() {
2838                             @Override
2839                             public void onTetheringFailed(final int result) {
2840                             }
2841                         });
2842                     verifyBridgedModeSoftApCallback(executor, callback,
2843                             shouldFallbackToSingleAp, true /* enabled */);
2844                     // stop tethering which used to verify stopSoftAp
2845                     mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
2846                     verifyBridgedModeSoftApCallback(executor, callback,
2847                             shouldFallbackToSingleAp, false /* disabled */);
2848                 }
2849             } finally {
2850                 mWifiManager.unregisterSoftApCallback(callback);
2851                 uiAutomation.dropShellPermissionIdentity();
2852             }
2853         }, false /* run with disabled */);
2854     }
2855 
2856     /**
2857      * Verify that the configuration from getSoftApConfiguration is same as the configuration which
2858      * set by setSoftApConfiguration. And depends softap capability callback to test different
2859      * configuration.
2860      * @throws Exception
2861      */
2862     @VirtualDeviceNotSupported
testSetGetSoftApConfigurationAndSoftApCapabilityCallback()2863     public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception {
2864         if (!WifiFeature.isWifiSupported(getContext())) {
2865             // skip the test if WiFi is not supported
2866             return;
2867         }
2868         // check that softap mode is supported by the device
2869         if (!mWifiManager.isPortableHotspotSupported()) {
2870             return;
2871         }
2872         if (shouldSkipCountryCodeDependentTest()) {
2873             // skip the test  when there is no Country Code available
2874             return;
2875         }
2876         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2877         TestExecutor executor = new TestExecutor();
2878         TestSoftApCallback callback = new TestSoftApCallback(mLock);
2879         try {
2880             uiAutomation.adoptShellPermissionIdentity();
2881             turnOffWifiAndTetheredHotspotIfEnabled();
2882             verifyRegisterSoftApCallback(executor, callback);
2883 
2884             SoftApConfiguration.Builder softApConfigBuilder =
2885                      generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
2886                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
2887                     .setAutoShutdownEnabled(true)
2888                     .setShutdownTimeoutMillis(100000)
2889                     .setBand(getAvailableBandAndChannelForTesting(
2890                             callback.getCurrentSoftApCapability()).keyAt(0))
2891                     .setHiddenSsid(false);
2892 
2893             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2894                 softApConfigBuilder.setBridgedModeOpportunisticShutdownTimeoutMillis(30_000);
2895                 softApConfigBuilder.setVendorElements(TEST_VENDOR_ELEMENTS);
2896                 softApConfigBuilder.setAllowedAcsChannels(
2897                         SoftApConfiguration.BAND_2GHZ, new int[] {1, 6, 11});
2898                 softApConfigBuilder.setAllowedAcsChannels(
2899                         SoftApConfiguration.BAND_5GHZ, new int[] {149});
2900                 softApConfigBuilder.setAllowedAcsChannels(
2901                         SoftApConfiguration.BAND_6GHZ, new int[] {});
2902                 softApConfigBuilder.setMaxChannelBandwidth(SoftApInfo.CHANNEL_WIDTH_80MHZ);
2903             }
2904 
2905             // Test SoftApConfiguration set and get
2906             verifySetGetSoftApConfig(softApConfigBuilder.build());
2907 
2908             boolean isSupportCustomizedMac = callback.getCurrentSoftApCapability()
2909                         .areFeaturesSupported(
2910                         SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION)
2911                     && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S);
2912 
2913             //Test MAC_ADDRESS_CUSTOMIZATION supported config
2914             if (isSupportCustomizedMac) {
2915                 softApConfigBuilder.setBssid(TEST_MAC)
2916                         .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE);
2917 
2918                 // Test SoftApConfiguration set and get
2919                 verifySetGetSoftApConfig(softApConfigBuilder.build());
2920             }
2921 
2922             // Test CLIENT_FORCE_DISCONNECT supported config.
2923             if (callback.getCurrentSoftApCapability()
2924                     .areFeaturesSupported(
2925                     SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) {
2926                 softApConfigBuilder.setMaxNumberOfClients(10);
2927                 softApConfigBuilder.setClientControlByUserEnabled(true);
2928                 softApConfigBuilder.setBlockedClientList(new ArrayList<>());
2929                 softApConfigBuilder.setAllowedClientList(new ArrayList<>());
2930                 verifySetGetSoftApConfig(softApConfigBuilder.build());
2931             }
2932 
2933             // Test SAE config
2934             if (callback.getCurrentSoftApCapability()
2935                     .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) {
2936                 softApConfigBuilder
2937                         .setPassphrase(TEST_PASSPHRASE,
2938                           SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
2939                 verifySetGetSoftApConfig(softApConfigBuilder.build());
2940                 softApConfigBuilder
2941                         .setPassphrase(TEST_PASSPHRASE,
2942                         SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
2943                 verifySetGetSoftApConfig(softApConfigBuilder.build());
2944             }
2945 
2946             // Test 11 BE control config
2947             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2948                 if (callback.getCurrentSoftApCapability()
2949                         .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE)) {
2950                     softApConfigBuilder.setIeee80211beEnabled(true);
2951                     verifySetGetSoftApConfig(softApConfigBuilder.build());
2952                 }
2953             }
2954 
2955             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
2956                 // Test 11 AX control config.
2957                 if (callback.getCurrentSoftApCapability()
2958                         .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX)) {
2959                     softApConfigBuilder.setIeee80211axEnabled(true);
2960                     verifySetGetSoftApConfig(softApConfigBuilder.build());
2961                 }
2962                 softApConfigBuilder.setBridgedModeOpportunisticShutdownEnabled(false);
2963                 verifySetGetSoftApConfig(softApConfigBuilder.build());
2964             }
2965 
2966         } finally {
2967             mWifiManager.unregisterSoftApCallback(callback);
2968             uiAutomation.dropShellPermissionIdentity();
2969         }
2970     }
2971 
2972     /**
2973      * Verify that startTetheredHotspot with specific channel config.
2974      * @throws Exception
2975      */
2976     @VirtualDeviceNotSupported
testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()2977     public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()
2978             throws Exception {
2979         if (!WifiFeature.isWifiSupported(getContext())) {
2980             // skip the test if WiFi is not supported
2981             return;
2982         }
2983         // check that softap mode is supported by the device
2984         if (!mWifiManager.isPortableHotspotSupported()) {
2985             return;
2986         }
2987         if (shouldSkipCountryCodeDependentTest()) {
2988             // skip the test  when there is no Country Code available
2989             return;
2990         }
2991         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2992         TestExecutor executor = new TestExecutor();
2993         TestSoftApCallback callback = new TestSoftApCallback(mLock);
2994         try {
2995             uiAutomation.adoptShellPermissionIdentity();
2996             // check that tethering is supported by the device
2997             if (!mTetheringManager.isTetheringSupported()) {
2998                 return;
2999             }
3000             turnOffWifiAndTetheredHotspotIfEnabled();
3001             verifyRegisterSoftApCallback(executor, callback);
3002 
3003             SparseIntArray testBandsAndChannels = getAvailableBandAndChannelForTesting(
3004                     callback.getCurrentSoftApCapability());
3005 
3006             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
3007                 assertNotEquals(0, testBandsAndChannels.size());
3008             }
3009             boolean isSupportCustomizedMac = callback.getCurrentSoftApCapability()
3010                     .areFeaturesSupported(
3011                     SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION)
3012                     && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S);
3013 
3014             SoftApConfiguration.Builder testSoftApConfigBuilder =
3015                      generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
3016                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
3017                     .setChannel(testBandsAndChannels.valueAt(0), testBandsAndChannels.keyAt(0));
3018 
3019             if (isSupportCustomizedMac) {
3020                 testSoftApConfigBuilder.setBssid(TEST_MAC)
3021                         .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE);
3022             }
3023 
3024             SoftApConfiguration testSoftApConfig = testSoftApConfigBuilder.build();
3025 
3026             mWifiManager.setSoftApConfiguration(testSoftApConfig);
3027 
3028             // start tethering which used to verify startTetheredHotspot
3029             mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
3030                 new TetheringManager.StartTetheringCallback() {
3031                     @Override
3032                     public void onTetheringFailed(final int result) {
3033                     }
3034                 });
3035 
3036             // Verify state and info callback value as expected
3037             PollingCheck.check(
3038                     "SoftAp channel and state mismatch!!!", 10_000,
3039                     () -> {
3040                         executor.runAll();
3041                         int sapChannel = ScanResult.convertFrequencyMhzToChannelIfSupported(
3042                                 callback.getCurrentSoftApInfo().getFrequency());
3043                         boolean isInfoCallbackSupported =
3044                                 callback.getOnSoftapInfoChangedCalledCount() > 1;
3045                         if (isInfoCallbackSupported) {
3046                             return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState()
3047                                 && testBandsAndChannels.valueAt(0) == sapChannel;
3048                         }
3049                         return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState();
3050                     });
3051             // After Soft Ap enabled, check SoftAp info if it supported
3052             if (isSupportCustomizedMac && callback.getOnSoftapInfoChangedCalledCount() > 1) {
3053                 assertEquals(callback.getCurrentSoftApInfo().getBssid(), TEST_MAC);
3054             }
3055             if (PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S)
3056                     && callback.getOnSoftapInfoChangedCalledCount() > 1) {
3057                 assertNotEquals(callback.getCurrentSoftApInfo().getWifiStandard(),
3058                         ScanResult.WIFI_STANDARD_UNKNOWN);
3059             }
3060 
3061             if (callback.getOnSoftapInfoChangedCalledCount() > 1) {
3062                 assertTrue(callback.getCurrentSoftApInfo().getAutoShutdownTimeoutMillis() > 0);
3063             }
3064         } finally {
3065             // stop tethering which used to verify stopSoftAp
3066             mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
3067 
3068             // Verify clean up
3069             PollingCheck.check(
3070                     "Stop Softap failed", 3_000,
3071                     () -> {
3072                         executor.runAll();
3073                         return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() &&
3074                                 0 == callback.getCurrentSoftApInfo().getBandwidth() &&
3075                                 0 == callback.getCurrentSoftApInfo().getFrequency();
3076                     });
3077             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
3078                 assertEquals(callback.getCurrentSoftApInfo().getBssid(), null);
3079                 assertEquals(ScanResult.WIFI_STANDARD_UNKNOWN,
3080                         callback.getCurrentSoftApInfo().getWifiStandard());
3081             }
3082             mWifiManager.unregisterSoftApCallback(callback);
3083             uiAutomation.dropShellPermissionIdentity();
3084         }
3085     }
3086 
3087     private static class TestActionListener implements WifiManager.ActionListener {
3088         private final Object mLock;
3089         public boolean onSuccessCalled = false;
3090         public boolean onFailedCalled = false;
3091         public int failureReason = -1;
3092 
TestActionListener(Object lock)3093         TestActionListener(Object lock) {
3094             mLock = lock;
3095         }
3096 
3097         @Override
onSuccess()3098         public void onSuccess() {
3099             synchronized (mLock) {
3100                 onSuccessCalled = true;
3101                 mLock.notify();
3102             }
3103         }
3104 
3105         @Override
onFailure(int reason)3106         public void onFailure(int reason) {
3107             synchronized (mLock) {
3108                 onFailedCalled = true;
3109                 failureReason = reason;
3110                 mLock.notify();
3111             }
3112         }
3113     }
3114 
3115     /**
3116      * Triggers connection to one of the saved networks using {@link WifiManager#connect(
3117      * int, WifiManager.ActionListener)} or {@link WifiManager#connect(WifiConfiguration,
3118      * WifiManager.ActionListener)}
3119      *
3120      * @param withNetworkId Use networkId for triggering connection, false for using
3121      *                      WifiConfiguration.
3122      * @throws Exception
3123      */
testConnect(boolean withNetworkId)3124     private void testConnect(boolean withNetworkId) throws Exception {
3125         TestActionListener actionListener = new TestActionListener(mLock);
3126         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3127         List<WifiConfiguration> savedNetworks = null;
3128         try {
3129             uiAutomation.adoptShellPermissionIdentity();
3130             // These below API's only work with privileged permissions (obtained via shell identity
3131             // for test)
3132             savedNetworks = mWifiManager.getConfiguredNetworks();
3133 
3134             // Disable all the saved networks to trigger disconnect & disable autojoin.
3135             for (WifiConfiguration network : savedNetworks) {
3136                 assertTrue(mWifiManager.disableNetwork(network.networkId));
3137             }
3138             waitForDisconnection();
3139 
3140             // Now trigger connection to the last saved network.
3141             WifiConfiguration savedNetworkToConnect =
3142                     savedNetworks.get(savedNetworks.size() - 1);
3143             synchronized (mLock) {
3144                 try {
3145                     if (withNetworkId) {
3146                         mWifiManager.connect(savedNetworkToConnect.networkId, actionListener);
3147                     } else {
3148                         mWifiManager.connect(savedNetworkToConnect, actionListener);
3149                     }
3150                     // now wait for callback
3151                     mLock.wait(TEST_WAIT_DURATION_MS);
3152                 } catch (InterruptedException e) {
3153                 }
3154             }
3155             // check if we got the success callback
3156             assertTrue(actionListener.onSuccessCalled);
3157             // Wait for connection to complete & ensure we are connected to the saved network.
3158             waitForConnection();
3159             assertEquals(savedNetworkToConnect.networkId,
3160                     mWifiManager.getConnectionInfo().getNetworkId());
3161         } finally {
3162             // Re-enable all saved networks before exiting.
3163             if (savedNetworks != null) {
3164                 for (WifiConfiguration network : savedNetworks) {
3165                     mWifiManager.enableNetwork(network.networkId, true);
3166                 }
3167             }
3168             uiAutomation.dropShellPermissionIdentity();
3169         }
3170     }
3171 
3172     /**
3173      * Tests {@link WifiManager#connect(int, WifiManager.ActionListener)} to an existing saved
3174      * network.
3175      */
testConnectWithNetworkId()3176     public void testConnectWithNetworkId() throws Exception {
3177         if (!WifiFeature.isWifiSupported(getContext())) {
3178             // skip the test if WiFi is not supported
3179             return;
3180         }
3181         testConnect(true);
3182     }
3183 
3184     /**
3185      * Tests {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)} to an
3186      * existing saved network.
3187      */
testConnectWithWifiConfiguration()3188     public void testConnectWithWifiConfiguration() throws Exception {
3189         if (!WifiFeature.isWifiSupported(getContext())) {
3190             // skip the test if WiFi is not supported
3191             return;
3192         }
3193         testConnect(false);
3194 
3195     }
3196 
3197     private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
3198         private final Object mLock;
3199         public boolean onAvailableCalled = false;
3200         public Network network;
3201         public NetworkCapabilities networkCapabilities;
3202 
TestNetworkCallback(Object lock)3203         TestNetworkCallback(Object lock) {
3204             mLock = lock;
3205         }
3206 
3207         @Override
onAvailable(Network network)3208         public void onAvailable(Network network) {
3209             synchronized (mLock) {
3210                 onAvailableCalled = true;
3211                 this.network = network;
3212             }
3213         }
3214 
3215         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)3216         public void onCapabilitiesChanged(Network network,
3217                 NetworkCapabilities networkCapabilities) {
3218             synchronized (mLock) {
3219                 this.networkCapabilities = networkCapabilities;
3220                 mLock.notify();
3221             }
3222         }
3223     }
3224 
waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered)3225     private void waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered) {
3226         TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock);
3227         synchronized (mLock) {
3228             try {
3229                 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder()
3230                         .addTransportType(TRANSPORT_WIFI);
3231                 if (expectMetered) {
3232                     networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_METERED);
3233                 } else {
3234                     networkRequestBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
3235                 }
3236                 // File a request for wifi network.
3237                 mConnectivityManager.registerNetworkCallback(
3238                         networkRequestBuilder.build(), networkCallbackListener);
3239                 // now wait for callback
3240                 mLock.wait(TEST_WAIT_DURATION_MS);
3241             } catch (InterruptedException e) {
3242             }
3243         }
3244         assertTrue(networkCallbackListener.onAvailableCalled);
3245     }
3246 
3247     /**
3248      * Tests {@link WifiManager#save(WifiConfiguration, WifiManager.ActionListener)} by marking
3249      * an existing saved network metered.
3250      */
testSave()3251     public void testSave() throws Exception {
3252         if (!WifiFeature.isWifiSupported(getContext())) {
3253             // skip the test if WiFi is not supported
3254             return;
3255         }
3256         TestActionListener actionListener = new TestActionListener(mLock);
3257         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3258         List<WifiConfiguration> savedNetworks = null;
3259         WifiConfiguration currentConfig = null;
3260         try {
3261             uiAutomation.adoptShellPermissionIdentity();
3262             // These below API's only work with privileged permissions (obtained via shell identity
3263             // for test)
3264 
3265             // Trigger a scan & wait for connection to one of the saved networks.
3266             mWifiManager.startScan();
3267             waitForConnection();
3268 
3269             WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
3270             savedNetworks = mWifiManager.getConfiguredNetworks();
3271 
3272             // find the current network's WifiConfiguration
3273             currentConfig = savedNetworks
3274                     .stream()
3275                     .filter(config -> config.networkId == wifiInfo.getNetworkId())
3276                     .findAny()
3277                     .get();
3278 
3279             // Ensure that the current network is not metered.
3280             assertNotEquals("Ensure that the saved network is configured as unmetered",
3281                     currentConfig.meteredOverride,
3282                     WifiConfiguration.METERED_OVERRIDE_METERED);
3283 
3284             // Disable all except the currently connected networks to avoid reconnecting to the
3285             // wrong network after later setting the current network as metered.
3286             for (WifiConfiguration network : savedNetworks) {
3287                 if (network.networkId != currentConfig.networkId) {
3288                     assertTrue(mWifiManager.disableNetwork(network.networkId));
3289                 }
3290             }
3291 
3292             // Check the network capabilities to ensure that the network is marked not metered.
3293             waitForNetworkCallbackAndCheckForMeteredness(false);
3294 
3295             // Now mark the network metered and save.
3296             synchronized (mLock) {
3297                 try {
3298                     WifiConfiguration modSavedNetwork = new WifiConfiguration(currentConfig);
3299                     modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
3300                     mWifiManager.save(modSavedNetwork, actionListener);
3301                     // now wait for callback
3302                     mLock.wait(TEST_WAIT_DURATION_MS);
3303                 } catch (InterruptedException e) {
3304                 }
3305             }
3306             // check if we got the success callback
3307             assertTrue(actionListener.onSuccessCalled);
3308             // Ensure we disconnected on marking the network metered & connect back.
3309             waitForDisconnection();
3310             waitForConnection();
3311             // Check the network capabilities to ensure that the network is marked metered now.
3312             waitForNetworkCallbackAndCheckForMeteredness(true);
3313 
3314         } finally {
3315             // Restore original network config (restore the meteredness back);
3316             if (currentConfig != null) {
3317                 mWifiManager.updateNetwork(currentConfig);
3318             }
3319             // re-enable all networks
3320             if (savedNetworks != null) {
3321                 for (WifiConfiguration network : savedNetworks) {
3322                     mWifiManager.enableNetwork(network.networkId, true);
3323                 }
3324             }
3325             uiAutomation.dropShellPermissionIdentity();
3326         }
3327     }
3328 
3329     /**
3330      * Tests {@link WifiManager#forget(int, WifiManager.ActionListener)} by adding/removing a new
3331      * network.
3332      */
3333     @AsbSecurityTest(cveBugId = 159373687)
testForget()3334     public void testForget() throws Exception {
3335         if (!WifiFeature.isWifiSupported(getContext())) {
3336             // skip the test if WiFi is not supported
3337             return;
3338         }
3339         TestActionListener actionListener = new TestActionListener(mLock);
3340         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3341         int newNetworkId = INVALID_NETWORK_ID;
3342         try {
3343             uiAutomation.adoptShellPermissionIdentity();
3344             // These below API's only work with privileged permissions (obtained via shell identity
3345             // for test)
3346             List<WifiConfiguration> savedNetworks = mWifiManager.getConfiguredNetworks();
3347 
3348             WifiConfiguration newOpenNetwork = new WifiConfiguration();
3349             newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\"";
3350             newNetworkId = mWifiManager.addNetwork(newOpenNetwork);
3351             assertNotEquals(INVALID_NETWORK_ID, newNetworkId);
3352 
3353             // Multi-type configurations might be converted to more than 1 configuration.
3354             assertThat(savedNetworks.size() < mWifiManager.getConfiguredNetworks().size()).isTrue();
3355 
3356             // Need an effectively-final holder because we need to modify inner Intent in callback.
3357             class IntentHolder {
3358                 Intent intent;
3359             }
3360             IntentHolder intentHolder = new IntentHolder();
3361             mContext.registerReceiver(new BroadcastReceiver() {
3362                 @Override
3363                 public void onReceive(Context context, Intent intent) {
3364                     Log.i(TAG, "Received CONFIGURED_NETWORKS_CHANGED_ACTION broadcast: " + intent);
3365                     intentHolder.intent = intent;
3366                 }
3367             }, new IntentFilter(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION));
3368 
3369             // Now remove the network
3370             synchronized (mLock) {
3371                 try {
3372                     mWifiManager.forget(newNetworkId, actionListener);
3373                     // now wait for callback
3374                     mLock.wait(TEST_WAIT_DURATION_MS);
3375                 } catch (InterruptedException e) {
3376                 }
3377             }
3378             // check if we got the success callback
3379             assertTrue(actionListener.onSuccessCalled);
3380 
3381             PollingCheck.check(
3382                     "Didn't receive CONFIGURED_NETWORKS_CHANGED_ACTION broadcast!",
3383                     TEST_WAIT_DURATION_MS,
3384                     () -> intentHolder.intent != null);
3385             Intent intent = intentHolder.intent;
3386             assertEquals(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION, intent.getAction());
3387             assertTrue(intent.getBooleanExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false));
3388             assertEquals(WifiManager.CHANGE_REASON_REMOVED,
3389                     intent.getIntExtra(WifiManager.EXTRA_CHANGE_REASON, -1));
3390             assertNull(intent.getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION));
3391 
3392             // Ensure that the new network has been successfully removed.
3393             assertEquals(savedNetworks.size(), mWifiManager.getConfiguredNetworks().size());
3394         } finally {
3395             // For whatever reason, if the forget fails, try removing using the public remove API.
3396             if (newNetworkId != INVALID_NETWORK_ID) mWifiManager.removeNetwork(newNetworkId);
3397             uiAutomation.dropShellPermissionIdentity();
3398         }
3399     }
3400 
3401     /**
3402      * Tests {@link WifiManager#getFactoryMacAddresses()} returns at least one valid MAC address.
3403      */
3404     @VirtualDeviceNotSupported
testGetFactoryMacAddresses()3405     public void testGetFactoryMacAddresses() throws Exception {
3406         if (!WifiFeature.isWifiSupported(getContext())) {
3407             // skip the test if WiFi is not supported
3408             return;
3409         }
3410         TestActionListener actionListener = new TestActionListener(mLock);
3411         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3412         int newNetworkId = INVALID_NETWORK_ID;
3413         try {
3414             uiAutomation.adoptShellPermissionIdentity();
3415             // Obtain the factory MAC address
3416             String[] macAddresses = mWifiManager.getFactoryMacAddresses();
3417             assertTrue("At list one MAC address should be returned.", macAddresses.length > 0);
3418             try {
3419                 MacAddress mac = MacAddress.fromString(macAddresses[0]);
3420                 assertNotEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mac);
3421                 assertFalse(MacAddressUtils.isMulticastAddress(mac));
3422             } catch (IllegalArgumentException e) {
3423                 fail("Factory MAC address is invalid");
3424             }
3425         } finally {
3426             uiAutomation.dropShellPermissionIdentity();
3427         }
3428     }
3429 
3430     /**
3431      * Tests {@link WifiManager#isApMacRandomizationSupported()} does not crash.
3432      */
testIsApMacRandomizationSupported()3433     public void testIsApMacRandomizationSupported() throws Exception {
3434         if (!WifiFeature.isWifiSupported(getContext())) {
3435             // skip the test if WiFi is not supported
3436             return;
3437         }
3438         mWifiManager.isApMacRandomizationSupported();
3439     }
3440 
3441     /**
3442      * Tests {@link WifiManager#isConnectedMacRandomizationSupported()} does not crash.
3443      */
testIsConnectedMacRandomizationSupported()3444     public void testIsConnectedMacRandomizationSupported() throws Exception {
3445         if (!WifiFeature.isWifiSupported(getContext())) {
3446             // skip the test if WiFi is not supported
3447             return;
3448         }
3449         mWifiManager.isConnectedMacRandomizationSupported();
3450     }
3451 
3452     /**
3453      * Tests {@link WifiManager#isPreferredNetworkOffloadSupported()} does not crash.
3454      */
testIsPreferredNetworkOffloadSupported()3455     public void testIsPreferredNetworkOffloadSupported() throws Exception {
3456         if (!WifiFeature.isWifiSupported(getContext())) {
3457             // skip the test if WiFi is not supported
3458             return;
3459         }
3460         mWifiManager.isPreferredNetworkOffloadSupported();
3461     }
3462 
3463     /** Test that PNO scans reconnects us when the device is disconnected and the screen is off. */
testPnoScan()3464     public void testPnoScan() throws Exception {
3465         if (!WifiFeature.isWifiSupported(getContext())) {
3466             // skip the test if WiFi is not supported
3467             return;
3468         }
3469         if (!mWifiManager.isPreferredNetworkOffloadSupported()) {
3470             // skip the test if PNO scanning is not supported
3471             return;
3472         }
3473 
3474         // make sure we're connected
3475         waitForConnection(WIFI_PNO_CONNECT_TIMEOUT_MILLIS);
3476 
3477         WifiInfo currentNetwork = ShellIdentityUtils.invokeWithShellPermissions(
3478                 mWifiManager::getConnectionInfo);
3479 
3480         // disable all networks that aren't already disabled
3481         List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
3482                 mWifiManager::getConfiguredNetworks);
3483         Set<Integer> disabledNetworkIds = new HashSet<>();
3484         for (WifiConfiguration config : savedNetworks) {
3485             if (config.getNetworkSelectionStatus().getNetworkSelectionDisableReason()
3486                     == WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE) {
3487                 ShellIdentityUtils.invokeWithShellPermissions(
3488                         () -> mWifiManager.disableNetwork(config.networkId));
3489                 disabledNetworkIds.add(config.networkId);
3490             }
3491         }
3492 
3493         try {
3494             // wait for disconnection from current network
3495             waitForDisconnection();
3496 
3497             // turn screen off
3498             turnScreenOffNoDelay();
3499 
3500             // re-enable the current network - this will trigger PNO
3501             ShellIdentityUtils.invokeWithShellPermissions(
3502                     () -> mWifiManager.enableNetwork(currentNetwork.getNetworkId(), false));
3503             disabledNetworkIds.remove(currentNetwork.getNetworkId());
3504 
3505             // PNO should reconnect us back to the network we disconnected from
3506             waitForConnection(WIFI_PNO_CONNECT_TIMEOUT_MILLIS);
3507         } finally {
3508             // re-enable disabled networks
3509             for (int disabledNetworkId : disabledNetworkIds) {
3510                 ShellIdentityUtils.invokeWithShellPermissions(
3511                         () -> mWifiManager.enableNetwork(disabledNetworkId, true));
3512             }
3513         }
3514     }
3515 
3516     /**
3517      * Tests {@link WifiManager#isTdlsSupported()} does not crash.
3518      */
testIsTdlsSupported()3519     public void testIsTdlsSupported() throws Exception {
3520         if (!WifiFeature.isWifiSupported(getContext())) {
3521             // skip the test if WiFi is not supported
3522             return;
3523         }
3524         mWifiManager.isTdlsSupported();
3525     }
3526 
3527     /**
3528      * Tests {@link WifiManager#isStaApConcurrencySupported().
3529      */
testIsStaApConcurrencySupported()3530     public void testIsStaApConcurrencySupported() throws Exception {
3531         if (!WifiFeature.isWifiSupported(getContext())) {
3532             // skip the test if WiFi is not supported
3533             return;
3534         }
3535         // check that softap mode is supported by the device
3536         if (!mWifiManager.isPortableHotspotSupported()) {
3537             return;
3538         }
3539         assertTrue(mWifiManager.isWifiEnabled());
3540 
3541         boolean isStaApConcurrencySupported = mWifiManager.isStaApConcurrencySupported();
3542         // start local only hotspot.
3543         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
3544         try {
3545             if (isStaApConcurrencySupported) {
3546                 assertTrue(mWifiManager.isWifiEnabled());
3547             } else {
3548                 // no concurrency, wifi should be disabled.
3549                 assertFalse(mWifiManager.isWifiEnabled());
3550             }
3551         } finally {
3552             // clean up local only hotspot no matter if assertion passed or failed
3553             stopLocalOnlyHotspot(callback, true);
3554         }
3555 
3556         assertTrue(mWifiManager.isWifiEnabled());
3557     }
3558 
3559     /**
3560      * state is a bitset, where bit 0 indicates whether there was data in, and bit 1 indicates
3561      * whether there was data out. Only count down on the latch once there was both data in and out.
3562      */
3563     private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback {
3564         public final CountDownLatch latch = new CountDownLatch(1);
3565         private int mAccumulator = 0;
3566 
3567         @Override
onStateChanged(int state)3568         public void onStateChanged(int state) {
3569             mAccumulator |= state;
3570             if (mAccumulator == DATA_ACTIVITY_INOUT) {
3571                 latch.countDown();
3572             }
3573         }
3574     }
3575 
sendTraffic()3576     private void sendTraffic() {
3577         boolean didAnyConnectionSucceed = false;
3578         for (int i = 0; i < 10; i++) {
3579             // Do some network operations
3580             HttpURLConnection connection = null;
3581             try {
3582                 URL url = new URL("http://www.google.com/");
3583                 connection = (HttpURLConnection) url.openConnection();
3584                 connection.setInstanceFollowRedirects(false);
3585                 connection.setConnectTimeout(TEST_WAIT_DURATION_MS);
3586                 connection.setReadTimeout(TEST_WAIT_DURATION_MS);
3587                 connection.setUseCaches(false);
3588                 InputStream stream = connection.getInputStream();
3589                 byte[] bytes = new byte[100];
3590                 int receivedBytes = stream.read(bytes);
3591                 if (receivedBytes > 0) {
3592                     didAnyConnectionSucceed = true;
3593                 }
3594             } catch (Exception e) {
3595                 // ignore
3596             } finally {
3597                 if (connection != null) connection.disconnect();
3598             }
3599         }
3600         assertTrue("All connections failed!", didAnyConnectionSucceed);
3601     }
3602 
3603     /**
3604      * Tests {@link WifiManager#registerTrafficStateCallback(Executor,
3605      * WifiManager.TrafficStateCallback)} by sending some traffic.
3606      */
testTrafficStateCallback()3607     public void testTrafficStateCallback() throws Exception {
3608         if (!WifiFeature.isWifiSupported(getContext())) {
3609             // skip the test if WiFi is not supported
3610             return;
3611         }
3612         TestTrafficStateCallback callback = new TestTrafficStateCallback();
3613         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3614         try {
3615             uiAutomation.adoptShellPermissionIdentity();
3616             // Trigger a scan & wait for connection to one of the saved networks.
3617             mWifiManager.startScan();
3618             waitForConnection();
3619 
3620             // Turn screen on for wifi traffic polling.
3621             turnScreenOn();
3622             mWifiManager.registerTrafficStateCallback(
3623                     Executors.newSingleThreadExecutor(), callback);
3624             // Send some traffic to trigger the traffic state change callbacks.
3625             sendTraffic();
3626             // now wait for callback
3627             boolean success = callback.latch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS);
3628             // check if we got the state changed callback with both data in and out
3629             assertTrue(success);
3630         } finally {
3631             turnScreenOff();
3632             mWifiManager.unregisterTrafficStateCallback(callback);
3633             uiAutomation.dropShellPermissionIdentity();
3634         }
3635     }
3636 
3637     /**
3638      * Tests {@link WifiManager#setScanAlwaysAvailable(boolean)} &
3639      * {@link WifiManager#isScanAlwaysAvailable()}.
3640      */
testScanAlwaysAvailable()3641     public void testScanAlwaysAvailable() throws Exception {
3642         if (!WifiFeature.isWifiSupported(getContext())) {
3643             // skip the test if WiFi is not supported
3644             return;
3645         }
3646         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3647         Boolean currState = null;
3648         try {
3649             uiAutomation.adoptShellPermissionIdentity();
3650             currState = mWifiManager.isScanAlwaysAvailable();
3651             boolean newState = !currState;
3652             mWifiManager.setScanAlwaysAvailable(newState);
3653             PollingCheck.check(
3654                     "Wifi settings toggle failed!",
3655                     DURATION_SETTINGS_TOGGLE,
3656                     () -> mWifiManager.isScanAlwaysAvailable() == newState);
3657             assertEquals(newState, mWifiManager.isScanAlwaysAvailable());
3658         } finally {
3659             if (currState != null) mWifiManager.setScanAlwaysAvailable(currState);
3660             uiAutomation.dropShellPermissionIdentity();
3661         }
3662     }
3663 
3664     /**
3665      * Tests {@link WifiManager#setScanThrottleEnabled(boolean)} &
3666      * {@link WifiManager#isScanThrottleEnabled()}.
3667      */
testScanThrottleEnabled()3668     public void testScanThrottleEnabled() throws Exception {
3669         if (!WifiFeature.isWifiSupported(getContext())) {
3670             // skip the test if WiFi is not supported
3671             return;
3672         }
3673         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3674         Boolean currState = null;
3675         try {
3676             uiAutomation.adoptShellPermissionIdentity();
3677             currState = mWifiManager.isScanThrottleEnabled();
3678             boolean newState = !currState;
3679             mWifiManager.setScanThrottleEnabled(newState);
3680             PollingCheck.check(
3681                     "Wifi settings toggle failed!",
3682                     DURATION_SETTINGS_TOGGLE,
3683                     () -> mWifiManager.isScanThrottleEnabled() == newState);
3684             assertEquals(newState, mWifiManager.isScanThrottleEnabled());
3685         } finally {
3686             if (currState != null) mWifiManager.setScanThrottleEnabled(currState);
3687             uiAutomation.dropShellPermissionIdentity();
3688         }
3689     }
3690 
3691     /**
3692      * Tests {@link WifiManager#setAutoWakeupEnabled(boolean)} &
3693      * {@link WifiManager#isAutoWakeupEnabled()}.
3694      */
testAutoWakeUpEnabled()3695     public void testAutoWakeUpEnabled() throws Exception {
3696         if (!WifiFeature.isWifiSupported(getContext())) {
3697             // skip the test if WiFi is not supported
3698             return;
3699         }
3700         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3701         Boolean currState = null;
3702         try {
3703             uiAutomation.adoptShellPermissionIdentity();
3704             currState = mWifiManager.isAutoWakeupEnabled();
3705             boolean newState = !currState;
3706             mWifiManager.setAutoWakeupEnabled(newState);
3707             PollingCheck.check(
3708                     "Wifi settings toggle failed!",
3709                     DURATION_SETTINGS_TOGGLE,
3710                     () -> mWifiManager.isAutoWakeupEnabled() == newState);
3711             assertEquals(newState, mWifiManager.isAutoWakeupEnabled());
3712         } finally {
3713             if (currState != null) mWifiManager.setAutoWakeupEnabled(currState);
3714             uiAutomation.dropShellPermissionIdentity();
3715         }
3716     }
3717 
3718     /**
3719      * Tests {@link WifiManager#setVerboseLoggingEnabled(boolean)} &
3720      * {@link WifiManager#isVerboseLoggingEnabled()}.
3721      */
testVerboseLoggingEnabled()3722     public void testVerboseLoggingEnabled() throws Exception {
3723         if (!WifiFeature.isWifiSupported(getContext())) {
3724             // skip the test if WiFi is not supported
3725             return;
3726         }
3727         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3728         Boolean currState = null;
3729         TestWifiVerboseLoggingStatusChangedListener listener =
3730                 WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext) ?
3731                 new TestWifiVerboseLoggingStatusChangedListener() : null;
3732         try {
3733             uiAutomation.adoptShellPermissionIdentity();
3734             if (listener != null) {
3735                 mWifiManager.addWifiVerboseLoggingStatusChangedListener(mExecutor, listener);
3736             }
3737             currState = mWifiManager.isVerboseLoggingEnabled();
3738             boolean newState = !currState;
3739             if (listener != null) {
3740                 assertEquals(0, listener.numCalls);
3741             }
3742             mWifiManager.setVerboseLoggingEnabled(newState);
3743             PollingCheck.check(
3744                     "Wifi verbose logging toggle failed!",
3745                     DURATION_SETTINGS_TOGGLE,
3746                     () -> mWifiManager.isVerboseLoggingEnabled() == newState);
3747             if (listener != null) {
3748                 PollingCheck.check(
3749                         "Verbose logging listener timeout",
3750                         DURATION_SETTINGS_TOGGLE,
3751                         () -> listener.status == newState && listener.numCalls == 1);
3752             }
3753         } finally {
3754             if (currState != null) mWifiManager.setVerboseLoggingEnabled(currState);
3755             if (listener != null) {
3756                 mWifiManager.removeWifiVerboseLoggingStatusChangedListener(listener);
3757             }
3758             uiAutomation.dropShellPermissionIdentity();
3759         }
3760     }
3761 
3762     /**
3763      * Tests {@link WifiManager#setVerboseLoggingLevel(int)}.
3764      */
testSetVerboseLogging()3765     public void testSetVerboseLogging() throws Exception {
3766         if (!WifiFeature.isWifiSupported(getContext())) {
3767             // skip the test if WiFi is not supported
3768             return;
3769         }
3770         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3771         Boolean currState = null;
3772         try {
3773             uiAutomation.adoptShellPermissionIdentity();
3774             currState = mWifiManager.isVerboseLoggingEnabled();
3775 
3776             mWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED);
3777             assertTrue(mWifiManager.isVerboseLoggingEnabled());
3778             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED,
3779                     mWifiManager.getVerboseLoggingLevel());
3780 
3781             mWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED);
3782             assertFalse(mWifiManager.isVerboseLoggingEnabled());
3783             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED,
3784                     mWifiManager.getVerboseLoggingLevel());
3785         } finally {
3786             if (currState != null) mWifiManager.setVerboseLoggingEnabled(currState);
3787             uiAutomation.dropShellPermissionIdentity();
3788         }
3789     }
3790 
3791     /**
3792      * Test {@link WifiManager#setVerboseLoggingLevel(int)} for show key mode.
3793      */
3794     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testSetVerboseLoggingShowKeyModeNonUserBuild()3795     public void testSetVerboseLoggingShowKeyModeNonUserBuild() throws Exception {
3796         if (Build.TYPE.equals("user")) return;
3797         if (!WifiFeature.isWifiSupported(getContext())) {
3798             // skip the test if WiFi is not supported
3799             return;
3800         }
3801         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3802         Boolean currState = null;
3803         try {
3804             uiAutomation.adoptShellPermissionIdentity();
3805             currState = mWifiManager.isVerboseLoggingEnabled();
3806 
3807             mWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY);
3808             assertTrue(mWifiManager.isVerboseLoggingEnabled());
3809             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY,
3810                     mWifiManager.getVerboseLoggingLevel());
3811         } finally {
3812             if (currState != null) mWifiManager.setVerboseLoggingEnabled(currState);
3813             uiAutomation.dropShellPermissionIdentity();
3814         }
3815     }
3816 
3817     /**
3818      * Test {@link WifiManager#setVerboseLoggingLevel(int)} for show key mode.
3819      */
3820     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testSetVerboseLoggingShowKeyModeUserBuild()3821     public void testSetVerboseLoggingShowKeyModeUserBuild() throws Exception {
3822         if (!Build.TYPE.equals("user")) return;
3823         if (!WifiFeature.isWifiSupported(getContext())) {
3824             // skip the test if WiFi is not supported
3825             return;
3826         }
3827         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3828         Boolean currState = null;
3829         try {
3830             uiAutomation.adoptShellPermissionIdentity();
3831             currState = mWifiManager.isVerboseLoggingEnabled();
3832 
3833             mWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY);
3834             assertTrue(mWifiManager.isVerboseLoggingEnabled());
3835             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY,
3836                     mWifiManager.getVerboseLoggingLevel());
3837             fail("Verbosing logging show key mode should not be allowed for user build.");
3838         } catch (SecurityException e) {
3839             // expected
3840         } finally {
3841             if (currState != null) mWifiManager.setVerboseLoggingEnabled(currState);
3842             uiAutomation.dropShellPermissionIdentity();
3843         }
3844     }
3845 
3846     /**
3847      * Tests {@link WifiManager#factoryReset()} cannot be invoked from a non-privileged app.
3848      *
3849      * Note: This intentionally does not test the full reset functionality because it causes
3850      * the existing saved networks on the device to be lost after the test. If you add the
3851      * networks back after reset, the ownership of saved networks will change.
3852      */
testFactoryReset()3853     public void testFactoryReset() throws Exception {
3854         if (!WifiFeature.isWifiSupported(getContext())) {
3855             // skip the test if WiFi is not supported
3856             return;
3857         }
3858         List<WifiConfiguration> beforeSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
3859                 mWifiManager::getConfiguredNetworks);
3860         try {
3861             mWifiManager.factoryReset();
3862             fail("Factory reset should not be allowed for non-privileged apps");
3863         } catch (SecurityException e) {
3864             // expected
3865         }
3866         List<WifiConfiguration> afterSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
3867                 mWifiManager::getConfiguredNetworks);
3868         assertEquals(beforeSavedNetworks.size(), afterSavedNetworks.size());
3869     }
3870 
3871     /**
3872      * Test {@link WifiNetworkConnectionStatistics} does not crash.
3873      * TODO(b/150891569): deprecate it in Android S, this API is not used anywhere.
3874      */
testWifiNetworkConnectionStatistics()3875     public void testWifiNetworkConnectionStatistics() {
3876         if (!WifiFeature.isWifiSupported(getContext())) {
3877             // skip the test if WiFi is not supported
3878             return;
3879         }
3880         new WifiNetworkConnectionStatistics();
3881         WifiNetworkConnectionStatistics stats = new WifiNetworkConnectionStatistics(0, 0);
3882         new WifiNetworkConnectionStatistics(stats);
3883     }
3884 
3885     /**
3886      * Verify that startRestrictingAutoJoinToSubscriptionId disconnects wifi and disables
3887      * auto-connect to non-carrier-merged networks. Then verify that
3888      * stopRestrictingAutoJoinToSubscriptionId makes the disabled networks clear to connect
3889      * again.
3890      */
3891     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testStartAndStopRestrictingAutoJoinToSubscriptionId()3892     public void testStartAndStopRestrictingAutoJoinToSubscriptionId() throws Exception {
3893         if (!WifiFeature.isWifiSupported(getContext())) {
3894             // skip the test if WiFi is not supported
3895             return;
3896         }
3897         startScan();
3898         waitForConnection();
3899         int fakeSubscriptionId = 5;
3900         ShellIdentityUtils.invokeWithShellPermissions(() ->
3901                 mWifiManager.startRestrictingAutoJoinToSubscriptionId(fakeSubscriptionId));
3902         startScan();
3903         ensureNotConnected();
3904         ShellIdentityUtils.invokeWithShellPermissions(() ->
3905                 mWifiManager.stopRestrictingAutoJoinToSubscriptionId());
3906         startScan();
3907         waitForConnection();
3908     }
3909 
3910     private class TestActiveCountryCodeChangedCallback implements
3911             WifiManager.ActiveCountryCodeChangedCallback  {
3912         private String mCurrentCountryCode;
3913         private boolean mIsOnActiveCountryCodeChangedCalled = false;
3914         private boolean mIsOnCountryCodeInactiveCalled = false;
3915 
isOnActiveCountryCodeChangedCalled()3916         public boolean isOnActiveCountryCodeChangedCalled() {
3917             return mIsOnActiveCountryCodeChangedCalled;
3918         }
3919 
isOnCountryCodeInactiveCalled()3920         public boolean isOnCountryCodeInactiveCalled() {
3921             return mIsOnCountryCodeInactiveCalled;
3922         }
resetCallbackCallededHistory()3923         public void resetCallbackCallededHistory() {
3924             mIsOnActiveCountryCodeChangedCalled = false;
3925             mIsOnCountryCodeInactiveCalled = false;
3926         }
3927 
getCurrentDriverCountryCode()3928         public String getCurrentDriverCountryCode() {
3929             return mCurrentCountryCode;
3930         }
3931 
3932         @Override
onActiveCountryCodeChanged(String country)3933         public void onActiveCountryCodeChanged(String country) {
3934             Log.d(TAG, "Receive DriverCountryCodeChanged to " + country);
3935             mCurrentCountryCode = country;
3936             mIsOnActiveCountryCodeChangedCalled = true;
3937         }
3938 
3939         @Override
onCountryCodeInactive()3940         public void onCountryCodeInactive() {
3941             Log.d(TAG, "Receive onCountryCodeInactive");
3942             mCurrentCountryCode = null;
3943             mIsOnCountryCodeInactiveCalled = true;
3944         }
3945     }
3946 
3947     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testActiveCountryCodeChangedCallback()3948     public void testActiveCountryCodeChangedCallback() throws Exception {
3949         if (!hasLocationFeature()) {
3950             // skip the test if location is not supported
3951             return;
3952         }
3953         if (!isLocationEnabled()) {
3954             fail("Please enable location for this test - since country code is not available"
3955                     + " when location is disabled!");
3956         }
3957         if (shouldSkipCountryCodeDependentTest()) {
3958             // skip the test when there is no Country Code available
3959             return;
3960         }
3961         TestActiveCountryCodeChangedCallback testCountryCodeChangedCallback =
3962                 new TestActiveCountryCodeChangedCallback();
3963         TestExecutor executor = new TestExecutor();
3964         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3965         try {
3966             uiAutomation.adoptShellPermissionIdentity();
3967             turnOffWifiAndTetheredHotspotIfEnabled();
3968             // Run with scanning disable to make sure there is no active mode.
3969             runWithScanning(() -> {
3970                 mWifiManager.registerActiveCountryCodeChangedCallback(
3971                         executor, testCountryCodeChangedCallback);
3972 
3973 
3974                 PollingCheck.check(
3975                         "DriverCountryCode is non-null when wifi off",
3976                         5000,
3977                         () -> {
3978                             executor.runAll();
3979                             return testCountryCodeChangedCallback
3980                                         .isOnCountryCodeInactiveCalled()
3981                                     && testCountryCodeChangedCallback.getCurrentDriverCountryCode()
3982                                             == null;
3983                         });
3984                 // Enable wifi to make sure country code has been updated.
3985                 setWifiEnabled(true);
3986                 PollingCheck.check(
3987                         "DriverCountryCode is null when wifi on",
3988                         5000,
3989                         () -> {
3990                             executor.runAll();
3991                             return testCountryCodeChangedCallback
3992                                         .isOnActiveCountryCodeChangedCalled()
3993                                     && testCountryCodeChangedCallback.getCurrentDriverCountryCode()
3994                                             != null;
3995                         });
3996                 // Disable wifi to trigger country code change
3997                 setWifiEnabled(false);
3998                 PollingCheck.check(
3999                         "DriverCountryCode should be null when wifi off",
4000                         5000,
4001                         () -> {
4002                             executor.runAll();
4003                             return testCountryCodeChangedCallback.isOnCountryCodeInactiveCalled()
4004                                     && testCountryCodeChangedCallback
4005                                             .getCurrentDriverCountryCode() == null;
4006                         });
4007                 mWifiManager.unregisterActiveCountryCodeChangedCallback(
4008                             testCountryCodeChangedCallback);
4009                 testCountryCodeChangedCallback.resetCallbackCallededHistory();
4010                 setWifiEnabled(true);
4011                 // Check there is no callback has been called.
4012                 PollingCheck.check(
4013                         "Callback is called after unregister",
4014                         5000,
4015                         () -> {
4016                             executor.runAll();
4017                             return !testCountryCodeChangedCallback.isOnCountryCodeInactiveCalled()
4018                                     && !testCountryCodeChangedCallback
4019                                             .isOnActiveCountryCodeChangedCalled();
4020                         });
4021             }, false /* Run with disabled */);
4022         } finally {
4023             uiAutomation.dropShellPermissionIdentity();
4024         }
4025     }
4026 
4027     /**
4028      * Test that the wifi country code is either null, or a length-2 string.
4029      */
testGetCountryCode()4030     public void testGetCountryCode() throws Exception {
4031         if (!WifiFeature.isWifiSupported(getContext())) {
4032             // skip the test if WiFi is not supported
4033             return;
4034         }
4035 
4036         String wifiCountryCode = ShellIdentityUtils.invokeWithShellPermissions(
4037                 mWifiManager::getCountryCode);
4038 
4039         if (wifiCountryCode == null) {
4040             return;
4041         }
4042         assertEquals(2, wifiCountryCode.length());
4043 
4044         // assert that the country code is all uppercase
4045         assertEquals(wifiCountryCode.toUpperCase(Locale.US), wifiCountryCode);
4046 
4047         // skip if Telephony is unsupported
4048         if (!WifiFeature.isTelephonySupported(getContext())) {
4049             return;
4050         }
4051 
4052         String telephonyCountryCode = getContext().getSystemService(TelephonyManager.class)
4053                 .getNetworkCountryIso();
4054 
4055         // skip if Telephony country code is unavailable
4056         if (telephonyCountryCode == null || telephonyCountryCode.isEmpty()) {
4057             return;
4058         }
4059 
4060         assertEquals(telephonyCountryCode, wifiCountryCode.toLowerCase(Locale.US));
4061     }
4062 
4063     /**
4064      * Test that {@link WifiManager#getCurrentNetwork()} returns a Network obeject consistent
4065      * with {@link ConnectivityManager#registerNetworkCallback} when connected to a Wifi network,
4066      * and returns null when not connected.
4067      */
testGetCurrentNetwork()4068     public void testGetCurrentNetwork() throws Exception {
4069         if (!WifiFeature.isWifiSupported(getContext())) {
4070             // skip the test if WiFi is not supported
4071             return;
4072         }
4073 
4074         // ensure Wifi is connected
4075         ShellIdentityUtils.invokeWithShellPermissions(() -> mWifiManager.reconnect());
4076         PollingCheck.check(
4077                 "Wifi not connected - Please ensure there is a saved network in range of this "
4078                         + "device",
4079                 WIFI_CONNECT_TIMEOUT_MILLIS,
4080                 () -> mWifiManager.getConnectionInfo().getNetworkId() != -1);
4081 
4082         String networkKey = mWifiManager.getConnectionInfo().getNetworkKey();
4083         assertNotNull(networkKey);
4084 
4085         Network wifiCurrentNetwork = ShellIdentityUtils.invokeWithShellPermissions(
4086                 mWifiManager::getCurrentNetwork);
4087         assertNotNull(wifiCurrentNetwork);
4088 
4089         List<WifiConfiguration> configuredNetwork = ShellIdentityUtils.invokeWithShellPermissions(
4090                 mWifiManager::getConfiguredNetworks);
4091 
4092         boolean isNetworkKeyExist = false;
4093         for (WifiConfiguration config : configuredNetwork) {
4094             if (config.getAllNetworkKeys().contains(networkKey)) {
4095                 isNetworkKeyExist = true;
4096                 break;
4097             }
4098         }
4099 
4100         assertTrue(isNetworkKeyExist);
4101 
4102         TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock);
4103         synchronized (mLock) {
4104             try {
4105                 // File a request for wifi network.
4106                 mConnectivityManager.registerNetworkCallback(
4107                         new NetworkRequest.Builder()
4108                                 .addTransportType(TRANSPORT_WIFI)
4109                                 .build(),
4110                         networkCallbackListener);
4111                 // now wait for callback
4112                 mLock.wait(TEST_WAIT_DURATION_MS);
4113             } catch (InterruptedException e) {
4114             }
4115         }
4116         assertTrue(networkCallbackListener.onAvailableCalled);
4117         Network connectivityCurrentNetwork = networkCallbackListener.network;
4118         assertEquals(connectivityCurrentNetwork, wifiCurrentNetwork);
4119 
4120         setWifiEnabled(false);
4121         PollingCheck.check(
4122                 "Wifi not disconnected!",
4123                 20000,
4124                 () -> mWifiManager.getConnectionInfo().getNetworkId() == -1);
4125 
4126         assertNull(ShellIdentityUtils.invokeWithShellPermissions(mWifiManager::getCurrentNetwork));
4127     }
4128 
4129     /**
4130      * Tests {@link WifiManager#isWpa3SaeSupported()} does not crash.
4131      */
testIsWpa3SaeSupported()4132     public void testIsWpa3SaeSupported() throws Exception {
4133         if (!WifiFeature.isWifiSupported(getContext())) {
4134             // skip the test if WiFi is not supported
4135             return;
4136         }
4137         mWifiManager.isWpa3SaeSupported();
4138     }
4139 
4140     /**
4141      * Tests {@link WifiManager#isWpa3SuiteBSupported()} does not crash.
4142      */
testIsWpa3SuiteBSupported()4143     public void testIsWpa3SuiteBSupported() throws Exception {
4144         if (!WifiFeature.isWifiSupported(getContext())) {
4145             // skip the test if WiFi is not supported
4146             return;
4147         }
4148         mWifiManager.isWpa3SuiteBSupported();
4149     }
4150 
4151     /**
4152      * Tests {@link WifiManager#isEnhancedOpenSupported()} does not crash.
4153      */
testIsEnhancedOpenSupported()4154     public void testIsEnhancedOpenSupported() throws Exception {
4155         if (!WifiFeature.isWifiSupported(getContext())) {
4156             // skip the test if WiFi is not supported
4157             return;
4158         }
4159         mWifiManager.isEnhancedOpenSupported();
4160     }
4161 
4162     /**
4163      * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in
4164      * both WiFi enabled/disabled states.
4165      * Note that the response depends on device support and hence both true/false
4166      * are valid responses.
4167      */
testIs5GhzBandSupported()4168     public void testIs5GhzBandSupported() throws Exception {
4169         if (!WifiFeature.isWifiSupported(getContext())) {
4170             // skip the test if WiFi is not supported
4171             return;
4172         }
4173 
4174         // Check for 5GHz support with wifi enabled
4175         setWifiEnabled(true);
4176         PollingCheck.check(
4177                 "Wifi not enabled!",
4178                 20000,
4179                 () -> mWifiManager.isWifiEnabled());
4180         boolean isSupportedEnabled = mWifiManager.is5GHzBandSupported();
4181 
4182         // Check for 5GHz support with wifi disabled
4183         setWifiEnabled(false);
4184         PollingCheck.check(
4185                 "Wifi not disabled!",
4186                 20000,
4187                 () -> !mWifiManager.isWifiEnabled());
4188         boolean isSupportedDisabled = mWifiManager.is5GHzBandSupported();
4189 
4190         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
4191         // Note, the reverse is a valid case.
4192         if (isSupportedDisabled) {
4193             assertTrue(isSupportedEnabled);
4194         }
4195     }
4196 
4197     /**
4198      * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in
4199      * both Wifi enabled/disabled states.
4200      * Note that the response depends on device support and hence both true/false
4201      * are valid responses.
4202      */
testIs6GhzBandSupported()4203     public void testIs6GhzBandSupported() throws Exception {
4204         if (!WifiFeature.isWifiSupported(getContext())) {
4205             // skip the test if WiFi is not supported
4206             return;
4207         }
4208 
4209         // Check for 6GHz support with wifi enabled
4210         setWifiEnabled(true);
4211         PollingCheck.check(
4212                 "Wifi not enabled!",
4213                 20000,
4214                 () -> mWifiManager.isWifiEnabled());
4215         boolean isSupportedEnabled = mWifiManager.is6GHzBandSupported();
4216 
4217         // Check for 6GHz support with wifi disabled
4218         setWifiEnabled(false);
4219         PollingCheck.check(
4220                 "Wifi not disabled!",
4221                 20000,
4222                 () -> !mWifiManager.isWifiEnabled());
4223         boolean isSupportedDisabled = mWifiManager.is6GHzBandSupported();
4224 
4225         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
4226         // Note, the reverse is a valid case.
4227         if (isSupportedDisabled) {
4228             assertTrue(isSupportedEnabled);
4229         }
4230     }
4231 
4232     /**
4233      * Test that {@link WifiManager#is60GHzBandSupported()} returns successfully in
4234      * both Wifi enabled/disabled states.
4235      * Note that the response depends on device support and hence both true/false
4236      * are valid responses.
4237      */
testIs60GhzBandSupported()4238     public void testIs60GhzBandSupported() throws Exception {
4239         if (!(WifiFeature.isWifiSupported(getContext())
4240                 && ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S))) {
4241             // skip the test if WiFi is not supported
4242             return;
4243         }
4244 
4245         // Check for 60GHz support with wifi enabled
4246         setWifiEnabled(true);
4247         PollingCheck.check(
4248                 "Wifi not enabled!",
4249                 20000,
4250                 () -> mWifiManager.isWifiEnabled());
4251         boolean isSupportedEnabled = mWifiManager.is60GHzBandSupported();
4252 
4253         // Check for 60GHz support with wifi disabled
4254         setWifiEnabled(false);
4255         PollingCheck.check(
4256                 "Wifi not disabled!",
4257                 20000,
4258                 () -> !mWifiManager.isWifiEnabled());
4259         boolean isSupportedDisabled = mWifiManager.is60GHzBandSupported();
4260 
4261         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
4262         // Note, the reverse is a valid case.
4263         if (isSupportedDisabled) {
4264             assertTrue(isSupportedEnabled);
4265         }
4266     }
4267 
4268     /**
4269      * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in
4270      * both Wifi enabled/disabled states. The test is to be performed on
4271      * {@link WifiAnnotations}'s {@code WIFI_STANDARD_}
4272      * Note that the response depends on device support and hence both true/false
4273      * are valid responses.
4274      */
testIsWifiStandardsSupported()4275     public void testIsWifiStandardsSupported() throws Exception {
4276         if (!WifiFeature.isWifiSupported(getContext())) {
4277             // skip the test if WiFi is not supported
4278             return;
4279         }
4280 
4281         // Check for WiFi standards support with wifi enabled
4282         setWifiEnabled(true);
4283         PollingCheck.check(
4284                 "Wifi not enabled!",
4285                 20000,
4286                 () -> mWifiManager.isWifiEnabled());
4287         boolean isLegacySupportedEnabled =
4288                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
4289         boolean is11nSupporedEnabled =
4290                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
4291         boolean is11acSupportedEnabled =
4292                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
4293         boolean is11axSupportedEnabled =
4294                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
4295         boolean is11beSupportedEnabled =
4296                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE);
4297 
4298         // Check for WiFi standards support with wifi disabled
4299         setWifiEnabled(false);
4300         PollingCheck.check(
4301                 "Wifi not disabled!",
4302                 20000,
4303                 () -> !mWifiManager.isWifiEnabled());
4304 
4305         boolean isLegacySupportedDisabled =
4306                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
4307         boolean is11nSupportedDisabled =
4308                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
4309         boolean is11acSupportedDisabled =
4310                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
4311         boolean is11axSupportedDisabled =
4312                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
4313         boolean is11beSupportedDisabled =
4314                 mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE);
4315 
4316         if (isLegacySupportedDisabled) {
4317             assertTrue(isLegacySupportedEnabled);
4318         }
4319 
4320         if (is11nSupportedDisabled) {
4321             assertTrue(is11nSupporedEnabled);
4322         }
4323 
4324         if (is11acSupportedDisabled) {
4325             assertTrue(is11acSupportedEnabled);
4326         }
4327 
4328         if (is11axSupportedDisabled) {
4329             assertTrue(is11axSupportedEnabled);
4330         }
4331 
4332         if (is11beSupportedDisabled) {
4333             assertTrue(is11beSupportedEnabled);
4334         }
4335     }
4336 
createPasspointConfiguration()4337     private static PasspointConfiguration createPasspointConfiguration() {
4338         PasspointConfiguration config = new PasspointConfiguration();
4339         HomeSp homeSp = new HomeSp();
4340         homeSp.setFqdn("test.com");
4341         homeSp.setFriendlyName("friendly name");
4342         homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66});
4343         config.setHomeSp(homeSp);
4344         Credential.SimCredential simCred = new Credential.SimCredential();
4345         simCred.setImsi("123456*");
4346         simCred.setEapType(23 /* EAP_AKA */);
4347         Credential cred = new Credential();
4348         cred.setRealm("realm");
4349         cred.setSimCredential(simCred);
4350         config.setCredential(cred);
4351 
4352         return config;
4353     }
4354 
4355     /**
4356      * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)}
4357      * adds a Passpoint configuration correctly by getting it once it is added, and comparing it
4358      * to the local copy of the configuration.
4359      */
testAddOrUpdatePasspointConfiguration()4360     public void testAddOrUpdatePasspointConfiguration() throws Exception {
4361         if (!WifiFeature.isWifiSupported(getContext())) {
4362             // skip the test if WiFi is not supported
4363             return;
4364         }
4365 
4366         // Create and install a Passpoint configuration
4367         PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
4368         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4369         try {
4370             uiAutomation.adoptShellPermissionIdentity();
4371             mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
4372 
4373             // Compare configurations
4374             List<PasspointConfiguration> configurations = mWifiManager.getPasspointConfigurations();
4375             assertNotNull("The installed passpoint profile is missing", configurations);
4376             assertEquals(passpointConfiguration, getTargetPasspointConfiguration(configurations,
4377                     passpointConfiguration.getUniqueId()));
4378         } finally {
4379             // Clean up
4380             mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn());
4381             uiAutomation.dropShellPermissionIdentity();
4382         }
4383     }
4384 
4385     /**
4386      * Tests {@link WifiManager#setPasspointMeteredOverride(String, int)}
4387      * adds a Passpoint configuration correctly, check the default metered setting. Use API change
4388      * metered override, verify Passpoint configuration changes with it.
4389      */
testSetPasspointMeteredOverride()4390     public void testSetPasspointMeteredOverride() throws Exception {
4391         if (!WifiFeature.isWifiSupported(getContext())) {
4392             // skip the test if WiFi is not supported
4393             return;
4394         }
4395         // Create and install a Passpoint configuration
4396         PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
4397         String fqdn = passpointConfiguration.getHomeSp().getFqdn();
4398         String uniqueId = passpointConfiguration.getUniqueId();
4399         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4400 
4401         try {
4402             uiAutomation.adoptShellPermissionIdentity();
4403             mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
4404             PasspointConfiguration saved = getTargetPasspointConfiguration(
4405                     mWifiManager.getPasspointConfigurations(), uniqueId);
4406             assertNotNull("The installed passpoint profile is missing", saved);
4407             // Verify meter override setting.
4408             assertEquals("Metered overrider default should be none",
4409                     WifiConfiguration.METERED_OVERRIDE_NONE, saved.getMeteredOverride());
4410             // Change the meter override setting.
4411             mWifiManager.setPasspointMeteredOverride(fqdn,
4412                     WifiConfiguration.METERED_OVERRIDE_METERED);
4413             // Verify passpoint config change with the new setting.
4414             saved = getTargetPasspointConfiguration(
4415                     mWifiManager.getPasspointConfigurations(), uniqueId);
4416             assertNotNull("The installed passpoint profile is missing", saved);
4417             assertEquals("Metered override should be metered",
4418                     WifiConfiguration.METERED_OVERRIDE_METERED, saved.getMeteredOverride());
4419         } finally {
4420             // Clean up
4421             mWifiManager.removePasspointConfiguration(fqdn);
4422             uiAutomation.dropShellPermissionIdentity();
4423         }
4424     }
4425 
4426     /**
4427      * Tests that
4428      * {@link WifiManager#startSubscriptionProvisioning(OsuProvider, Executor, ProvisioningCallback)}
4429      * starts a subscription provisioning, and confirm a status callback invoked once.
4430      */
testStartSubscriptionProvisioning()4431     public void testStartSubscriptionProvisioning() throws Exception {
4432         if (!WifiFeature.isWifiSupported(getContext())) {
4433             // skip the test if WiFi is not supported
4434             return;
4435         }
4436 
4437         // Using Java reflection to construct an OsuProvider instance because its constructor is
4438         // hidden and not available to apps.
4439         Class<?> osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider");
4440         Constructor<?> osuProviderClassConstructor = osuProviderClass.getConstructor(String.class,
4441                 Map.class, String.class, Uri.class, String.class, List.class);
4442 
4443         OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID,
4444                 TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI,
4445                 TEST_METHOD_LIST);
4446 
4447         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4448         try {
4449             uiAutomation.adoptShellPermissionIdentity();
4450             synchronized (mLock) {
4451                 // Start a subscription provisioning for a non-existent Passpoint R2 AP
4452                 mWifiManager.startSubscriptionProvisioning(osuProvider, mExecutor,
4453                         mProvisioningCallback);
4454                 mLock.wait(TEST_WAIT_DURATION_MS);
4455             }
4456         } finally {
4457             uiAutomation.dropShellPermissionIdentity();
4458         }
4459 
4460         // Expect only a single callback event, connecting. Since AP doesn't exist, it ends here
4461         assertEquals(ProvisioningCallback.OSU_STATUS_AP_CONNECTING, mProvisioningStatus);
4462         // No failure callbacks expected
4463         assertEquals(0, mProvisioningFailureStatus);
4464         // No completion callback expected
4465         assertFalse(mProvisioningComplete);
4466     }
4467 
4468     /**
4469      * Tests {@link WifiManager#setTdlsEnabled(InetAddress, boolean)} does not crash.
4470      */
testSetTdlsEnabled()4471     public void testSetTdlsEnabled() throws Exception {
4472         if (!WifiFeature.isWifiSupported(getContext())) {
4473             // skip the test if WiFi is not supported
4474             return;
4475         }
4476         // Trigger a scan & wait for connection to one of the saved networks.
4477         mWifiManager.startScan();
4478         waitForConnection();
4479 
4480         InetAddress inetAddress = InetAddress.getByName(TEST_IP_ADDRESS);
4481 
4482         mWifiManager.setTdlsEnabled(inetAddress, true);
4483         Thread.sleep(50);
4484         mWifiManager.setTdlsEnabled(inetAddress, false);
4485     }
4486 
4487     /**
4488      * Tests {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean)} does not crash.
4489      */
testSetTdlsEnabledWithMacAddress()4490     public void testSetTdlsEnabledWithMacAddress() throws Exception {
4491         if (!WifiFeature.isWifiSupported(getContext())) {
4492             // skip the test if WiFi is not supported
4493             return;
4494         }
4495         // Trigger a scan & wait for connection to one of the saved networks.
4496         mWifiManager.startScan();
4497         waitForConnection();
4498 
4499         mWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, true);
4500         Thread.sleep(50);
4501         mWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, false);
4502     }
4503 
4504     /**
4505      * Verify WifiNetworkSuggestion.Builder.setMacRandomizationSetting(WifiNetworkSuggestion
4506      * .RANDOMIZATION_NON_PERSISTENT) creates a
4507      * WifiConfiguration with macRandomizationSetting == RANDOMIZATION_NON_PERSISTENT.
4508      * Then verify by default, a WifiConfiguration created by suggestions should have
4509      * macRandomizationSetting == RANDOMIZATION_PERSISTENT.
4510      */
4511     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testSuggestionBuilderNonPersistentRandomization()4512     public void testSuggestionBuilderNonPersistentRandomization() throws Exception {
4513         if (!WifiFeature.isWifiSupported(getContext())) {
4514             // skip the test if WiFi is not supported
4515             return;
4516         }
4517         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
4518                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE)
4519                 .setMacRandomizationSetting(WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT)
4520                 .build();
4521         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
4522                 mWifiManager.addNetworkSuggestions(Arrays.asList(suggestion)));
4523         verifySuggestionFoundWithMacRandomizationSetting(TEST_SSID,
4524                 WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT);
4525 
4526         suggestion = new WifiNetworkSuggestion.Builder()
4527                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE)
4528                 .build();
4529         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
4530                 mWifiManager.addNetworkSuggestions(Arrays.asList(suggestion)));
4531         verifySuggestionFoundWithMacRandomizationSetting(TEST_SSID,
4532                 WifiNetworkSuggestion.RANDOMIZATION_PERSISTENT);
4533     }
4534 
verifySuggestionFoundWithMacRandomizationSetting(String ssid, int macRandomizationSetting)4535     private void verifySuggestionFoundWithMacRandomizationSetting(String ssid,
4536             int macRandomizationSetting) {
4537         List<WifiNetworkSuggestion> retrievedSuggestions = mWifiManager.getNetworkSuggestions();
4538         for (WifiNetworkSuggestion entry : retrievedSuggestions) {
4539             if (entry.getSsid().equals(ssid)) {
4540                 assertEquals(macRandomizationSetting, entry.getMacRandomizationSetting());
4541                 return; // pass test after the MAC randomization setting is verified.
4542             }
4543         }
4544         fail("WifiNetworkSuggestion not found for SSID=" + ssid + ", macRandomizationSetting="
4545                 + macRandomizationSetting);
4546     }
4547 
4548     /**
4549      * Tests {@link WifiManager#getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(List)}
4550      */
testGetAllWifiConfigForMatchedNetworkSuggestion()4551     public void testGetAllWifiConfigForMatchedNetworkSuggestion() {
4552         if (!WifiFeature.isWifiSupported(getContext())) {
4553             // skip the test if WiFi is not supported
4554             return;
4555         }
4556         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4557         ScanResult scanResult = new ScanResult();
4558         scanResult.SSID = TEST_SSID;
4559         scanResult.capabilities = TEST_PSK_CAP;
4560         scanResult.BSSID = TEST_BSSID;
4561         List<ScanResult> testList = Arrays.asList(scanResult);
4562         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
4563                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build();
4564 
4565         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
4566                 mWifiManager.addNetworkSuggestions(Arrays.asList(suggestion)));
4567         List<WifiConfiguration> matchedResult;
4568         try {
4569             uiAutomation.adoptShellPermissionIdentity();
4570             matchedResult = mWifiManager
4571                     .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(testList);
4572         } finally {
4573             uiAutomation.dropShellPermissionIdentity();
4574         }
4575         // As suggestion is not approved, will return empty list.
4576         assertTrue(matchedResult.isEmpty());
4577     }
4578 
4579     /**
4580      * Tests {@link WifiManager#getMatchingScanResults(List, List)}
4581      */
testGetMatchingScanResults()4582     public void testGetMatchingScanResults() {
4583         if (!WifiFeature.isWifiSupported(getContext())) {
4584             // skip the test if WiFi is not supported
4585             return;
4586         }
4587         // Create pair of ScanResult and WifiNetworkSuggestion
4588         ScanResult scanResult = new ScanResult();
4589         scanResult.SSID = TEST_SSID;
4590         scanResult.capabilities = TEST_PSK_CAP;
4591         scanResult.BSSID = TEST_BSSID;
4592 
4593         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
4594                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build();
4595 
4596         Map<WifiNetworkSuggestion, List<ScanResult>> matchedResults = mWifiManager
4597                 .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult));
4598         // Verify result is matched pair of ScanResult and WifiNetworkSuggestion
4599         assertEquals(scanResult.SSID, matchedResults.get(suggestion).get(0).SSID);
4600 
4601         // Change ScanResult to unmatched should return empty result.
4602         scanResult.SSID = TEST_SSID_UNQUOTED;
4603         matchedResults = mWifiManager
4604                 .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult));
4605         assertTrue(matchedResults.get(suggestion).isEmpty());
4606     }
4607 
4608     /**
4609      * Tests {@link WifiManager#disableEphemeralNetwork(String)}.
4610      */
testDisableEphemeralNetwork()4611     public void testDisableEphemeralNetwork() throws Exception {
4612         if (!WifiFeature.isWifiSupported(getContext())) {
4613             // skip the test if WiFi is not supported
4614             return;
4615         }
4616         // Trigger a scan & wait for connection to one of the saved networks.
4617         mWifiManager.startScan();
4618         waitForConnection();
4619 
4620         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4621         List<WifiConfiguration> savedNetworks = null;
4622         try {
4623             uiAutomation.adoptShellPermissionIdentity();
4624             // Temporarily disable on all networks.
4625             savedNetworks = mWifiManager.getConfiguredNetworks();
4626             for (WifiConfiguration network : savedNetworks) {
4627                 mWifiManager.disableEphemeralNetwork(network.SSID);
4628             }
4629             // trigger a disconnect and wait for disconnect.
4630             mWifiManager.disconnect();
4631             waitForDisconnection();
4632 
4633             // Now trigger scan and ensure that the device does not connect to any networks.
4634             mWifiManager.startScan();
4635             ensureNotConnected();
4636         } finally {
4637             uiAutomation.dropShellPermissionIdentity();
4638             setWifiEnabled(false);
4639         }
4640     }
4641 
4642     /**
4643      * Tests {@link WifiManager#allowAutojoin(int, boolean)}.
4644      */
testAllowAutojoin()4645     public void testAllowAutojoin() throws Exception {
4646         if (!WifiFeature.isWifiSupported(getContext())) {
4647             // skip the test if WiFi is not supported
4648             return;
4649         }
4650         // Trigger a scan & wait for connection to one of the saved networks.
4651         mWifiManager.startScan();
4652         waitForConnection();
4653 
4654         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4655         List<WifiConfiguration> savedNetworks = null;
4656         try {
4657             uiAutomation.adoptShellPermissionIdentity();
4658             // disable autojoin on all networks.
4659             savedNetworks = mWifiManager.getConfiguredNetworks();
4660             for (WifiConfiguration network : savedNetworks) {
4661                 mWifiManager.allowAutojoin(network.networkId, false);
4662             }
4663             // trigger a disconnect and wait for disconnect.
4664             mWifiManager.disconnect();
4665             waitForDisconnection();
4666 
4667             // Now trigger scan and ensure that the device does not connect to any networks.
4668             mWifiManager.startScan();
4669             ensureNotConnected();
4670 
4671             // Now enable autojoin on all networks.
4672             for (WifiConfiguration network : savedNetworks) {
4673                 mWifiManager.allowAutojoin(network.networkId, true);
4674             }
4675 
4676             // Trigger a scan & wait for connection to one of the saved networks.
4677             mWifiManager.startScan();
4678             waitForConnection();
4679         } finally {
4680             // Restore auto join state.
4681             if (savedNetworks != null) {
4682                 for (WifiConfiguration network : savedNetworks) {
4683                     mWifiManager.allowAutojoin(network.networkId, network.allowAutojoin);
4684                 }
4685             }
4686             uiAutomation.dropShellPermissionIdentity();
4687         }
4688     }
4689 
4690     /**
4691      * Tests {@link WifiManager#allowAutojoinPasspoint(String, boolean)}.
4692      */
testAllowAutojoinPasspoint()4693     public void testAllowAutojoinPasspoint() throws Exception {
4694         if (!WifiFeature.isWifiSupported(getContext())) {
4695             // skip the test if WiFi is not supported
4696             return;
4697         }
4698 
4699         PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
4700         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4701         try {
4702             uiAutomation.adoptShellPermissionIdentity();
4703             mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
4704             // Turn off auto-join
4705             mWifiManager.allowAutojoinPasspoint(
4706                     passpointConfiguration.getHomeSp().getFqdn(), false);
4707             // Turn on auto-join
4708             mWifiManager.allowAutojoinPasspoint(
4709                     passpointConfiguration.getHomeSp().getFqdn(), true);
4710         } finally {
4711             mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn());
4712             uiAutomation.dropShellPermissionIdentity();
4713         }
4714     }
4715 
4716     /**
4717      * Tests {@link WifiManager#allowAutojoinGlobal(boolean)}.
4718      */
testAllowAutojoinGlobal()4719     public void testAllowAutojoinGlobal() throws Exception {
4720         if (!WifiFeature.isWifiSupported(getContext())) {
4721             // skip the test if WiFi is not supported
4722             return;
4723         }
4724         // Trigger a scan & wait for connection to one of the saved networks.
4725         mWifiManager.startScan();
4726         waitForConnection();
4727 
4728         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4729         try {
4730             uiAutomation.adoptShellPermissionIdentity();
4731             // disable autojoin on all networks.
4732             mWifiManager.allowAutojoinGlobal(false);
4733 
4734             // trigger a disconnect and wait for disconnect.
4735             mWifiManager.disconnect();
4736             waitForDisconnection();
4737 
4738             // Now trigger scan and ensure that the device does not connect to any networks.
4739             mWifiManager.startScan();
4740             ensureNotConnected();
4741 
4742             // verify null is returned when attempting to get current configured network.
4743             WifiConfiguration config = mWifiManager.getPrivilegedConnectedNetwork();
4744             assertNull("config should be null because wifi is not connected", config);
4745 
4746             // Now enable autojoin on all networks.
4747             mWifiManager.allowAutojoinGlobal(true);
4748 
4749             // Trigger a scan & wait for connection to one of the saved networks.
4750             mWifiManager.startScan();
4751             waitForConnection();
4752         } finally {
4753             // Re-enable auto join if the test fails for some reason.
4754             mWifiManager.allowAutojoinGlobal(true);
4755             uiAutomation.dropShellPermissionIdentity();
4756         }
4757     }
4758 
4759     /**
4760      * Verify the invalid and valid usages of {@code WifiManager#queryAutojoinGlobal}.
4761      */
4762     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testQueryAutojoinGlobal()4763     public void testQueryAutojoinGlobal() throws Exception {
4764         if (!WifiFeature.isWifiSupported(getContext())) {
4765             // skip the test if WiFi is not supported
4766             return;
4767         }
4768 
4769         AtomicBoolean enabled = new AtomicBoolean(false);
4770         Consumer<Boolean> listener = new Consumer<Boolean>() {
4771             @Override
4772             public void accept(Boolean value) {
4773                 synchronized (mLock) {
4774                     enabled.set(value);
4775                     mLock.notify();
4776                 }
4777             }
4778         };
4779         // Test invalid inputs trigger IllegalArgumentException
4780         assertThrows("null executor should trigger exception", NullPointerException.class,
4781                 () -> mWifiManager.queryAutojoinGlobal(null, listener));
4782         assertThrows("null listener should trigger exception", NullPointerException.class,
4783                 () -> mWifiManager.queryAutojoinGlobal(mExecutor, null));
4784 
4785         // Test caller with no permission triggers SecurityException.
4786         assertThrows("No permission should trigger SecurityException", SecurityException.class,
4787                 () -> mWifiManager.queryAutojoinGlobal(mExecutor, listener));
4788 
4789         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4790         try {
4791             uiAutomation.adoptShellPermissionIdentity();
4792             // Test get/set autojoin global enabled
4793             mWifiManager.allowAutojoinGlobal(true);
4794             mWifiManager.queryAutojoinGlobal(mExecutor, listener);
4795             synchronized (mLock) {
4796                 mLock.wait(TEST_WAIT_DURATION_MS);
4797             }
4798             assertTrue(enabled.get());
4799 
4800             // Test get/set autojoin global disabled
4801             mWifiManager.allowAutojoinGlobal(false);
4802             mWifiManager.queryAutojoinGlobal(mExecutor, listener);
4803             synchronized (mLock) {
4804                 mLock.wait(TEST_WAIT_DURATION_MS);
4805             }
4806             assertFalse(enabled.get());
4807         } finally {
4808             // Re-enable auto join if the test fails for some reason.
4809             mWifiManager.allowAutojoinGlobal(true);
4810             uiAutomation.dropShellPermissionIdentity();
4811         }
4812     }
4813 
4814     /**
4815      * Tests {@link WifiManager#isWapiSupported()} does not crash.
4816      */
testIsWapiSupported()4817     public void testIsWapiSupported() throws Exception {
4818         if (!WifiFeature.isWifiSupported(getContext())) {
4819             // skip the test if WiFi is not supported
4820             return;
4821         }
4822         mWifiManager.isWapiSupported();
4823     }
4824 
4825     /**
4826      * Tests {@link WifiManager#isWpa3SaePublicKeySupported()} does not crash.
4827      */
4828     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testIsWpa3SaePublicKeySupported()4829     public void testIsWpa3SaePublicKeySupported() throws Exception {
4830         if (!WifiFeature.isWifiSupported(getContext())) {
4831             // skip the test if WiFi is not supported
4832             return;
4833         }
4834         mWifiManager.isWpa3SaePublicKeySupported();
4835     }
4836 
4837     /**
4838      * Tests {@link WifiManager#isWpa3SaeH2eSupported()} does not crash.
4839      */
4840     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testIsWpa3SaeH2eSupported()4841     public void testIsWpa3SaeH2eSupported() throws Exception {
4842         if (!WifiFeature.isWifiSupported(getContext())) {
4843             // skip the test if WiFi is not supported
4844             return;
4845         }
4846         mWifiManager.isWpa3SaeH2eSupported();
4847     }
4848 
4849     /**
4850      * Tests {@link WifiManager#isWifiDisplayR2Supported()} does not crash.
4851      */
4852     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testIsWifiDisplayR2Supported()4853     public void testIsWifiDisplayR2Supported() throws Exception {
4854         if (!WifiFeature.isWifiSupported(getContext())) {
4855             // skip the test if WiFi is not supported
4856             return;
4857         }
4858         mWifiManager.isWifiDisplayR2Supported();
4859     }
4860 
4861     /**
4862      * Tests {@link WifiManager#isP2pSupported()} returns true
4863      * if this device supports it, otherwise, ensure no crash.
4864      */
testIsP2pSupported()4865     public void testIsP2pSupported() throws Exception {
4866         if (!WifiFeature.isWifiSupported(getContext())) {
4867             // skip the test if WiFi is not supported
4868             return;
4869         }
4870 
4871         if (WifiFeature.isP2pSupported(getContext())) {
4872             // if this device supports P2P, ensure hw capability is correct.
4873             assertTrue(mWifiManager.isP2pSupported());
4874         } else {
4875             // ensure no crash.
4876             mWifiManager.isP2pSupported();
4877         }
4878 
4879     }
4880 
4881     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testIsMultiStaConcurrencySupported()4882     public void testIsMultiStaConcurrencySupported() throws Exception {
4883         if (!WifiFeature.isWifiSupported(getContext())) {
4884             // skip the test if WiFi is not supported
4885             return;
4886         }
4887         // ensure no crash.
4888         mWifiManager.isStaApConcurrencySupported();
4889     }
4890 
getTargetPasspointConfiguration( List<PasspointConfiguration> configurationList, String uniqueId)4891     private PasspointConfiguration getTargetPasspointConfiguration(
4892             List<PasspointConfiguration> configurationList, String uniqueId) {
4893         if (configurationList == null || configurationList.isEmpty()) {
4894             return null;
4895         }
4896         for (PasspointConfiguration config : configurationList) {
4897             if (TextUtils.equals(config.getUniqueId(), uniqueId)) {
4898                 return config;
4899             }
4900         }
4901         return null;
4902     }
4903 
4904     /**
4905      * Test that {@link WifiManager#is60GHzBandSupported()} throws UnsupportedOperationException
4906      * if the release is older than S.
4907      */
4908     @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.R)
testIs60GhzBandSupportedOnROrOlder()4909     public void testIs60GhzBandSupportedOnROrOlder() throws Exception {
4910         if (!WifiFeature.isWifiSupported(getContext())) {
4911             // skip the test if WiFi is not supported
4912             return;
4913         }
4914 
4915         // check for 60ghz support with wifi enabled
4916         try {
4917             boolean isSupported = mWifiManager.is60GHzBandSupported();
4918             fail("Expected UnsupportedOperationException");
4919         } catch (UnsupportedOperationException ex) {
4920         }
4921 
4922     }
4923 
4924     /**
4925      * Test that {@link WifiManager#is60GHzBandSupported()} returns successfully in
4926      * both Wifi enabled/disabled states for release newer than R.
4927      * Note that the response depends on device support and hence both true/false
4928      * are valid responses.
4929      */
4930     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testIs60GhzBandSupportedOnSOrNewer()4931     public void testIs60GhzBandSupportedOnSOrNewer() throws Exception {
4932         if (!WifiFeature.isWifiSupported(getContext())) {
4933             // skip the test if WiFi is not supported
4934             return;
4935         }
4936 
4937         // check for 60ghz support with wifi enabled
4938         boolean isSupportedWhenWifiEnabled = mWifiManager.is60GHzBandSupported();
4939 
4940         // Check for 60GHz support with wifi disabled
4941         setWifiEnabled(false);
4942         PollingCheck.check(
4943                 "Wifi not disabled!",
4944                 20000,
4945                 () -> !mWifiManager.isWifiEnabled());
4946         boolean isSupportedWhenWifiDisabled = mWifiManager.is60GHzBandSupported();
4947 
4948         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
4949         // Note, the reverse is a valid case.
4950         if (isSupportedWhenWifiDisabled) {
4951             assertTrue(isSupportedWhenWifiEnabled);
4952         }
4953     }
4954 
4955     /**
4956      * Tests {@link WifiManager#isTrustOnFirstUseSupported()} does not crash.
4957      */
4958     // TODO(b/196180536): Wait for T SDK finalization before changing
4959     // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)`
4960     @SdkSuppress(minSdkVersion = 31)
testIsTrustOnFirstUseSupported()4961     public void testIsTrustOnFirstUseSupported() throws Exception {
4962         if (!WifiFeature.isWifiSupported(getContext())) {
4963             // skip the test if WiFi is not supported
4964             return;
4965         }
4966         mWifiManager.isTrustOnFirstUseSupported();
4967     }
4968 
4969     public class TestCoexCallback extends WifiManager.CoexCallback {
4970         private Object mCoexLock;
4971         private int mOnCoexUnsafeChannelChangedCount;
4972         private List<CoexUnsafeChannel> mCoexUnsafeChannels;
4973         private int mCoexRestrictions;
4974 
TestCoexCallback(Object lock)4975         TestCoexCallback(Object lock) {
4976             mCoexLock = lock;
4977         }
4978 
4979         @Override
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, int restrictions)4980         public void onCoexUnsafeChannelsChanged(
4981                     @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) {
4982             synchronized (mCoexLock) {
4983                 mCoexUnsafeChannels = unsafeChannels;
4984                 mCoexRestrictions = restrictions;
4985                 mOnCoexUnsafeChannelChangedCount++;
4986                 mCoexLock.notify();
4987             }
4988         }
4989 
getOnCoexUnsafeChannelChangedCount()4990         public int getOnCoexUnsafeChannelChangedCount() {
4991             synchronized (mCoexLock) {
4992                 return mOnCoexUnsafeChannelChangedCount;
4993             }
4994         }
4995 
getCoexUnsafeChannels()4996         public List<CoexUnsafeChannel> getCoexUnsafeChannels() {
4997             return mCoexUnsafeChannels;
4998         }
4999 
getCoexRestrictions()5000         public int getCoexRestrictions() {
5001             return mCoexRestrictions;
5002         }
5003     }
5004 
5005     /**
5006      * Test that coex-related methods fail without the needed privileged permissions
5007      */
5008     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testCoexMethodsShouldFailNoPermission()5009     public void testCoexMethodsShouldFailNoPermission() {
5010         if (!WifiFeature.isWifiSupported(getContext())) {
5011             // skip the test if WiFi is not supported
5012             return;
5013         }
5014 
5015         try {
5016             mWifiManager.setCoexUnsafeChannels(Collections.emptyList(), 0);
5017             fail("setCoexUnsafeChannels should not succeed - privileged call");
5018         } catch (SecurityException e) {
5019             // expected
5020         }
5021         final TestCoexCallback callback = new TestCoexCallback(mLock);
5022         try {
5023             mWifiManager.registerCoexCallback(mExecutor, callback);
5024             fail("registerCoexCallback should not succeed - privileged call");
5025         } catch (SecurityException e) {
5026             // expected
5027         }
5028         try {
5029             mWifiManager.unregisterCoexCallback(callback);
5030             fail("unregisterCoexCallback should not succeed - privileged call");
5031         } catch (SecurityException e) {
5032             // expected
5033         }
5034     }
5035 
5036     /**
5037      * Test that coex-related methods succeed in setting the current unsafe channels and notifying
5038      * the listener. Since the default coex algorithm may be enabled, no-op is also valid behavior.
5039      */
5040     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testListenOnCoexUnsafeChannels()5041     public void testListenOnCoexUnsafeChannels() {
5042         if (!WifiFeature.isWifiSupported(getContext())) {
5043             // skip the test if WiFi is not supported
5044             return;
5045         }
5046 
5047         // These below API's only work with privileged permissions (obtained via shell identity
5048         // for test)
5049         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5050         List<CoexUnsafeChannel> prevUnsafeChannels = null;
5051         int prevRestrictions = -1;
5052         try {
5053             uiAutomation.adoptShellPermissionIdentity();
5054             final TestCoexCallback callback = new TestCoexCallback(mLock);
5055             final List<CoexUnsafeChannel> testUnsafeChannels = new ArrayList<>();
5056             testUnsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6));
5057             final int testRestrictions = COEX_RESTRICTION_WIFI_DIRECT
5058                     | COEX_RESTRICTION_SOFTAP | COEX_RESTRICTION_WIFI_AWARE;
5059             synchronized (mLock) {
5060                 try {
5061                     mWifiManager.registerCoexCallback(mExecutor, callback);
5062                     // Callback should be called after registering
5063                     mLock.wait(TEST_WAIT_DURATION_MS);
5064                     assertEquals(1, callback.getOnCoexUnsafeChannelChangedCount());
5065                     // Store the previous coex channels and set new coex channels
5066                     prevUnsafeChannels = callback.getCoexUnsafeChannels();
5067                     prevRestrictions = callback.getCoexRestrictions();
5068                     mWifiManager.setCoexUnsafeChannels(testUnsafeChannels, testRestrictions);
5069                     mLock.wait(TEST_WAIT_DURATION_MS);
5070                     // Unregister callback and try setting again
5071                     mWifiManager.unregisterCoexCallback(callback);
5072                     mWifiManager.setCoexUnsafeChannels(testUnsafeChannels, testRestrictions);
5073                     // Callback should not be called here since it was unregistered.
5074                     mLock.wait(TEST_WAIT_DURATION_MS);
5075                 } catch (InterruptedException e) {
5076                     fail("Thread interrupted unexpectedly while waiting on mLock");
5077                 }
5078             }
5079             if (callback.getOnCoexUnsafeChannelChangedCount() == 2) {
5080                 // Default algorithm disabled, setter should set the getter values.
5081                 assertEquals(testUnsafeChannels, callback.getCoexUnsafeChannels());
5082                 assertEquals(testRestrictions, callback.getCoexRestrictions());
5083             } else if (callback.getOnCoexUnsafeChannelChangedCount() != 1) {
5084                 fail("Coex callback called " + callback.mOnCoexUnsafeChannelChangedCount
5085                         + " times. Expected 0 or 1 calls." );
5086             }
5087         } finally {
5088             // Reset the previous unsafe channels if we overrode them.
5089             if (prevRestrictions != -1) {
5090                 mWifiManager.setCoexUnsafeChannels(prevUnsafeChannels, prevRestrictions);
5091             }
5092             uiAutomation.dropShellPermissionIdentity();
5093         }
5094     }
5095 
5096     /**
5097      * Verify that secure WPA-Enterprise network configurations can be added and updated.
5098      */
5099     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testSecureEnterpriseConfigurationsAccepted()5100     public void testSecureEnterpriseConfigurationsAccepted() throws Exception {
5101         if (!WifiFeature.isWifiSupported(getContext())) {
5102             // skip the test if WiFi is not supported
5103             return;
5104         }
5105         WifiConfiguration wifiConfiguration = new WifiConfiguration();
5106         wifiConfiguration.SSID = SSID1;
5107         wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
5108         wifiConfiguration.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
5109         int networkId = INVALID_NETWORK_ID;
5110 
5111         // These below API's only work with privileged permissions (obtained via shell identity
5112         // for test)
5113         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5114         try {
5115             uiAutomation.adoptShellPermissionIdentity();
5116 
5117             // Now configure it correctly with a Root CA cert and domain name
5118             wifiConfiguration.enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
5119             wifiConfiguration.enterpriseConfig.setAltSubjectMatch(TEST_DOM_SUBJECT_MATCH);
5120 
5121             // Verify that the network is added
5122             networkId = mWifiManager.addNetwork(wifiConfiguration);
5123             assertNotEquals(INVALID_NETWORK_ID, networkId);
5124 
5125             // Verify that the update API accepts configurations configured securely
5126             wifiConfiguration.networkId = networkId;
5127             assertEquals(networkId, mWifiManager.updateNetwork(wifiConfiguration));
5128         } finally {
5129             if (networkId != INVALID_NETWORK_ID) {
5130                 // Clean up the previously added network
5131                 mWifiManager.removeNetwork(networkId);
5132             }
5133             uiAutomation.dropShellPermissionIdentity();
5134         }
5135     }
5136 
5137     /**
5138      * Tests {@link WifiManager#isPasspointTermsAndConditionsSupported)} does not crash.
5139      */
testIsPasspointTermsAndConditionsSupported()5140     public void testIsPasspointTermsAndConditionsSupported() throws Exception {
5141         if (!WifiFeature.isWifiSupported(getContext())) {
5142             // skip the test if WiFi is not supported
5143             return;
5144         }
5145         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
5146             // Skip the test if wifi module version is older than S.
5147             return;
5148         }
5149         mWifiManager.isPasspointTermsAndConditionsSupported();
5150     }
5151 
5152     /**
5153      * Test that call to {@link WifiManager#setOverrideCountryCode()},
5154      * {@link WifiManager#clearOverrideCountryCode()} and
5155      * {@link WifiManager#setDefaultCountryCode()} need privileged permission
5156      * and the permission is not even given to shell user.
5157      */
5158     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testManageCountryCodeMethodsFailWithoutPermissions()5159     public void testManageCountryCodeMethodsFailWithoutPermissions() throws Exception {
5160         if (!WifiFeature.isWifiSupported(getContext())) {
5161             // skip the test if WiFi is not supported
5162             return;
5163         }
5164         ShellIdentityUtils.invokeWithShellPermissions(() -> {
5165             try {
5166                 mWifiManager.setOverrideCountryCode(TEST_COUNTRY_CODE);
5167                 fail("setOverrideCountryCode() expected to fail - privileged call");
5168             } catch (SecurityException e) {
5169                 // expected
5170             }
5171 
5172             try {
5173                 mWifiManager.clearOverrideCountryCode();
5174                 fail("clearOverrideCountryCode() expected to fail - privileged call");
5175             } catch (SecurityException e) {
5176                 // expected
5177             }
5178 
5179             try {
5180                 mWifiManager.setDefaultCountryCode(TEST_COUNTRY_CODE);
5181                 fail("setDefaultCountryCode() expected to fail - privileged call");
5182             } catch (SecurityException e) {
5183                 // expected
5184             }
5185         });
5186     }
5187 
5188     /**
5189      * Tests {@link WifiManager#flushPasspointAnqpCache)} does not crash.
5190      */
testFlushPasspointAnqpCache()5191     public void testFlushPasspointAnqpCache() throws Exception {
5192         if (!WifiFeature.isWifiSupported(getContext())) {
5193             // skip the test if WiFi is not supported
5194             return;
5195         }
5196         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
5197             // Skip the test if wifi module version is older than S.
5198             return;
5199         }
5200         // The below API only works with privileged permissions (obtained via shell identity
5201         // for test)
5202         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5203         try {
5204             uiAutomation.adoptShellPermissionIdentity();
5205             mWifiManager.flushPasspointAnqpCache();
5206         } finally {
5207             uiAutomation.dropShellPermissionIdentity();
5208         }
5209     }
5210 
5211     /**
5212      * Tests {@link WifiManager#setWifiPasspointEnabled)} raise security exception without
5213      * permission.
5214      */
5215     // TODO(b/139192273): Wait for T SDK finalization before changing
5216     // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.T)`
5217     @SdkSuppress(minSdkVersion = 31)
testEnablePasspointWithoutPermission()5218     public void testEnablePasspointWithoutPermission() throws Exception {
5219         if (!WifiFeature.isWifiSupported(getContext())) {
5220             // skip the test if WiFi is not supported
5221             return;
5222         }
5223         try {
5224             mWifiManager.setWifiPasspointEnabled(true);
5225             fail("setWifiPasspointEnabled() expected to fail - privileged call");
5226         } catch (SecurityException e) {
5227             // expected
5228         }
5229     }
5230 
5231     /**
5232      * Tests {@link WifiManager#setWifiPasspointEnabled)} does not crash and returns success.
5233      */
5234     // TODO(b/139192273): Wait for T SDK finalization before changing
5235     // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.T)`
5236     @SdkSuppress(minSdkVersion = 31)
testEnablePasspoint()5237     public void testEnablePasspoint() throws Exception {
5238         if (!WifiFeature.isWifiSupported(getContext())) {
5239             // skip the test if WiFi is not supported
5240             return;
5241         }
5242 
5243         // The below API only works with privileged permissions (obtained via shell identity
5244         // for test)
5245         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5246         try {
5247             uiAutomation.adoptShellPermissionIdentity();
5248             // Check if passpoint is enabled by default.
5249             assertTrue(mWifiManager.isWifiPasspointEnabled());
5250             // Try to disable passpoint
5251             mWifiManager.setWifiPasspointEnabled(false);
5252             PollingCheck.check(
5253                 "Wifi passpoint turn off failed!", 2_000,
5254                 () -> mWifiManager.isWifiPasspointEnabled() == false);
5255             // Try to enable passpoint
5256             mWifiManager.setWifiPasspointEnabled(true);
5257             PollingCheck.check(
5258                 "Wifi passpoint turn on failed!", 2_000,
5259                 () -> mWifiManager.isWifiPasspointEnabled() == true);
5260         } finally {
5261             uiAutomation.dropShellPermissionIdentity();
5262         }
5263     }
5264 
5265     /**
5266      * Tests {@link WifiManager#isDecoratedIdentitySupported)} does not crash.
5267      */
testIsDecoratedIdentitySupported()5268     public void testIsDecoratedIdentitySupported() throws Exception {
5269         if (!WifiFeature.isWifiSupported(getContext())) {
5270             // skip the test if WiFi is not supported
5271             return;
5272         }
5273         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
5274             // Skip the test if wifi module version is older than S.
5275             return;
5276         }
5277         mWifiManager.isDecoratedIdentitySupported();
5278     }
5279 
5280     /**
5281      * Tests {@link WifiManager#setCarrierNetworkOffloadEnabled)} and
5282      * {@link WifiManager#isCarrierNetworkOffloadEnabled} work as expected.
5283      */
testSetCarrierNetworkOffloadEnabled()5284     public void testSetCarrierNetworkOffloadEnabled() {
5285         if (!WifiFeature.isWifiSupported(getContext())
5286                 || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
5287             // skip the test if WiFi is not supported
5288             return;
5289         }
5290         assertTrue(mWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
5291         // The below API only works with privileged permissions (obtained via shell identity
5292         // for test)
5293         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5294         try {
5295             uiAutomation.adoptShellPermissionIdentity();
5296             mWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, false, false);
5297             assertFalse(mWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
5298         } finally {
5299             mWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, false, true);
5300             uiAutomation.dropShellPermissionIdentity();
5301         }
5302         assertTrue(mWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
5303     }
5304 
5305    /**
5306      * Test that {@link WifiManager#getUsableChannels(int, int)},
5307      * {@link WifiManager#getAllowedChannels(int, int)}
5308      * throws UnsupportedOperationException if the release is older than S.
5309      */
5310     @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.R)
testGetAllowedUsableChannelsOnROrOlder()5311     public void testGetAllowedUsableChannelsOnROrOlder() throws Exception {
5312         if (!WifiFeature.isWifiSupported(getContext())) {
5313             // skip the test if WiFi is not supported
5314             return;
5315         }
5316         try {
5317             mWifiManager.getAllowedChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5318             fail("getAllowedChannels Expected to fail - UnsupportedOperationException");
5319         } catch (UnsupportedOperationException ex) {}
5320 
5321         try {
5322             mWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5323             fail("getUsableChannels Expected to fail - UnsupportedOperationException");
5324         } catch (UnsupportedOperationException ex) {}
5325     }
5326 
5327     /**
5328      * Tests {@link WifiManager#getAllowedChannels(int, int))} does not crash
5329      */
5330     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testGetAllowedChannels()5331     public void testGetAllowedChannels() throws Exception {
5332         if (!WifiFeature.isWifiSupported(getContext())) {
5333             // skip the test if WiFi is not supported
5334             return;
5335         }
5336         // The below API only works with privileged permissions (obtained via shell identity
5337         // for test)
5338         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5339         try {
5340 
5341             WifiAvailableChannel channel = new WifiAvailableChannel(2412, OP_MODE_SAP);
5342             assertEquals(channel.getFrequencyMhz(), 2412);
5343             assertEquals(channel.getOperationalModes(), OP_MODE_SAP);
5344             final List<Integer> valid24GhzFreqs = Arrays.asList(
5345                 2412, 2417, 2422, 2427, 2432, 2437, 2442,
5346                 2447, 2452, 2457, 2462, 2467, 2472, 2484);
5347             Set<Integer> supported24GhzFreqs = new HashSet<Integer>();
5348             uiAutomation.adoptShellPermissionIdentity();
5349             List<WifiAvailableChannel> allowedChannels =
5350                 mWifiManager.getAllowedChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5351             assertNotNull(allowedChannels);
5352             for (WifiAvailableChannel ch : allowedChannels) {
5353                 //Must contain a valid 2.4GHz frequency
5354                 assertTrue(valid24GhzFreqs.contains(ch.getFrequencyMhz()));
5355                 if(ch.getFrequencyMhz() <= 2462) {
5356                     //Channels 1-11 are supported for STA in all countries
5357                     assertEquals(ch.getOperationalModes() & OP_MODE_STA, OP_MODE_STA);
5358                     supported24GhzFreqs.add(ch.getFrequencyMhz());
5359                 }
5360             }
5361             //Channels 1-11 are supported for STA in all countries
5362             assertEquals(supported24GhzFreqs.size(), 11);
5363         } catch (UnsupportedOperationException ex) {
5364             //expected if the device does not support this API
5365         } catch (Exception ex) {
5366             fail("getAllowedChannels unexpected Exception " + ex);
5367         } finally {
5368             uiAutomation.dropShellPermissionIdentity();
5369         }
5370     }
5371 
5372     /**
5373      * Tests {@link WifiManager#getUsableChannels(int, int))} does not crash.
5374      */
5375     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testGetUsableChannels()5376     public void testGetUsableChannels() throws Exception {
5377         if (!WifiFeature.isWifiSupported(getContext())) {
5378             // skip the test if WiFi is not supported
5379             return;
5380         }
5381         // The below API only works with privileged permissions (obtained via shell identity
5382         // for test)
5383         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5384         try {
5385             uiAutomation.adoptShellPermissionIdentity();
5386             List<WifiAvailableChannel> usableChannels =
5387                 mWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5388             //There must be at least one usable channel in 2.4GHz band
5389             assertFalse(usableChannels.isEmpty());
5390         } catch (UnsupportedOperationException ex) {
5391             //expected if the device does not support this API
5392         } catch (Exception ex) {
5393             fail("getUsableChannels unexpected Exception " + ex);
5394         } finally {
5395             uiAutomation.dropShellPermissionIdentity();
5396         }
5397     }
5398 
5399     /**
5400      * Validate that the Passpoint feature is enabled on the device.
5401      */
5402     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testPasspointCapability()5403     public void testPasspointCapability() {
5404         if (!WifiFeature.isWifiSupported(getContext())) {
5405             // skip the test if WiFi is not supported
5406             return;
5407         }
5408         PackageManager packageManager = mContext.getPackageManager();
5409         assertTrue("Passpoint must be supported",
5410                 packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT));
5411     }
5412 
5413     /**
5414      * Validate add and remove SuggestionUserApprovalStatusListener. And verify the listener's
5415      * stickiness.
5416      */
testAddRemoveSuggestionUserApprovalStatusListener()5417     public void testAddRemoveSuggestionUserApprovalStatusListener() throws Exception {
5418         if (!WifiFeature.isWifiSupported(getContext())
5419                 || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
5420             return;
5421         }
5422         CountDownLatch countDownLatch = new CountDownLatch(1);
5423         TestUserApprovalStatusListener listener = new TestUserApprovalStatusListener(
5424                 countDownLatch);
5425         try {
5426             mWifiManager.addSuggestionUserApprovalStatusListener(mExecutor, listener);
5427             assertTrue(countDownLatch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS));
5428         } finally {
5429             mWifiManager.removeSuggestionUserApprovalStatusListener(listener);
5430         }
5431     }
5432 
5433     private static class TestUserApprovalStatusListener implements
5434             WifiManager.SuggestionUserApprovalStatusListener {
5435         private final CountDownLatch mBlocker;
5436 
TestUserApprovalStatusListener(CountDownLatch countDownLatch)5437         public TestUserApprovalStatusListener(CountDownLatch countDownLatch) {
5438             mBlocker = countDownLatch;
5439         }
5440         @Override
onUserApprovalStatusChange(int status)5441         public void onUserApprovalStatusChange(int status) {
5442             mBlocker.countDown();
5443         }
5444     }
5445 
5446     /**
5447      * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} raise security exception
5448      * without permission.
5449      */
5450     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testIsStaConcurrencyForMultiInternetSupported()5451     public void testIsStaConcurrencyForMultiInternetSupported() throws Exception {
5452         if (!WifiFeature.isWifiSupported(getContext())) {
5453             // skip the test if WiFi is not supported
5454             return;
5455         }
5456         // ensure no crash.
5457         mWifiManager.isStaConcurrencyForMultiInternetSupported();
5458     }
5459 
5460     /**
5461      * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} raise security exception
5462      * without permission.
5463      */
5464     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetStaConcurrencyForMultiInternetModeWithoutPermission()5465     public void testSetStaConcurrencyForMultiInternetModeWithoutPermission() throws Exception {
5466         if (!WifiFeature.isWifiSupported(getContext())
5467                 || !mWifiManager.isStaConcurrencyForMultiInternetSupported()) {
5468             // skip the test if WiFi is not supported or multi internet feature not supported.
5469             return;
5470         }
5471         try {
5472             mWifiManager.setStaConcurrencyForMultiInternetMode(
5473                     WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED);
5474             fail("setWifiPasspointEnabled() expected to fail - privileged call");
5475         } catch (SecurityException e) {
5476             // expected
5477         }
5478     }
5479 
5480     /**
5481      * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} does not crash.
5482      */
5483     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testSetStaConcurrencyForMultiInternetMode()5484     public void testSetStaConcurrencyForMultiInternetMode() throws Exception {
5485         if (!WifiFeature.isWifiSupported(getContext())
5486                 || !mWifiManager.isStaConcurrencyForMultiInternetSupported()) {
5487             // skip the test if WiFi is not supported or multi internet feature not supported.
5488             return;
5489         }
5490 
5491         // The below API only works with privileged permissions (obtained via shell identity
5492         // for test)
5493         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5494         try {
5495             uiAutomation.adoptShellPermissionIdentity();
5496             // Try to disable multi internet
5497             mWifiManager.setStaConcurrencyForMultiInternetMode(
5498                     WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED);
5499             PollingCheck.check(
5500                     "Wifi multi internet disable failed!", 2_000,
5501                     () -> mWifiManager.getStaConcurrencyForMultiInternetMode()
5502                             == WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED);
5503             // Try to enable multi internet
5504             mWifiManager.setStaConcurrencyForMultiInternetMode(
5505                     WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP);
5506             PollingCheck.check(
5507                     "Wifi multi internet turn on failed!", 2_000,
5508                     () -> mWifiManager.getStaConcurrencyForMultiInternetMode()
5509                             == WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP);
5510         } finally {
5511             uiAutomation.dropShellPermissionIdentity();
5512         }
5513     }
5514 
5515     /**
5516      * Tests {@link WifiConfiguration#setBssidAllowlist(List)}.
5517      */
5518     @ApiTest(apis = "android.net.wifi.WifiConfiguration#setBssidAllowlist")
testBssidAllowlist()5519     public void testBssidAllowlist() throws Exception {
5520         if (!WifiFeature.isWifiSupported(getContext())) {
5521             // skip the test if WiFi is not supported
5522             return;
5523         }
5524         // Trigger a scan & wait for connection to one of the saved networks.
5525         mWifiManager.startScan();
5526         waitForConnection();
5527 
5528         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5529         List<WifiConfiguration> savedNetworks = null;
5530         try {
5531             uiAutomation.adoptShellPermissionIdentity();
5532 
5533             WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
5534             String connectedBssid = wifiInfo.getBSSID();
5535             int networkId = wifiInfo.getNetworkId();
5536 
5537             // Set empty BSSID allow list to block all APs
5538             savedNetworks = mWifiManager.getConfiguredNetworks();
5539             for (WifiConfiguration network : savedNetworks) {
5540                 network.setBssidAllowlist(Collections.emptyList());
5541                 mWifiManager.updateNetwork(network);
5542             }
5543 
5544             // Disable and re-enable Wifi to avoid reconnect to the secondary candidate
5545             setWifiEnabled(false);
5546             setWifiEnabled(true);
5547 
5548             // Now trigger scan and ensure that the device does not connect to any networks.
5549             mWifiManager.startScan();
5550             ensureNotConnected();
5551 
5552             // Set the previous connected BSSID on that network. Other network set with a fake
5553             // (not visible) BSSID only
5554             for (WifiConfiguration network : savedNetworks) {
5555                 if (network.networkId == networkId) {
5556                     network.setBssidAllowlist(List.of(MacAddress.fromString(connectedBssid)));
5557                     mWifiManager.updateNetwork(network);
5558                 } else {
5559                     network.setBssidAllowlist(List.of(MacAddress.fromString(TEST_BSSID)));
5560                     mWifiManager.updateNetwork(network);
5561                 }
5562             }
5563 
5564             // Trigger a scan & wait for connection to one of the saved networks.
5565             mWifiManager.startScan();
5566             waitForConnection();
5567             wifiInfo = mWifiManager.getConnectionInfo();
5568             assertEquals(networkId, wifiInfo.getNetworkId());
5569         } finally {
5570             // Reset BSSID allow list to accept all APs
5571             for (WifiConfiguration network : savedNetworks) {
5572                 assertNotNull(network.getBssidAllowlist());
5573                 network.setBssidAllowlist(null);
5574                 mWifiManager.updateNetwork(network);
5575             }
5576             uiAutomation.dropShellPermissionIdentity();
5577         }
5578     }
5579 
5580     /**
5581      * Tests {@link WifiManager#notifyMinimumRequiredWifiSecurityLevelChanged(int)}
5582      * raise security exception without permission.
5583      */
5584     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testNotifyMinimumRequiredWifiSecurityLevelChangedWithoutPermission()5585     public void testNotifyMinimumRequiredWifiSecurityLevelChangedWithoutPermission()
5586             throws Exception {
5587         if (!WifiFeature.isWifiSupported(getContext())) {
5588             // skip the test if WiFi is not supported.
5589             return;
5590         }
5591         assertThrows(SecurityException.class,
5592                 () -> mWifiManager.notifyMinimumRequiredWifiSecurityLevelChanged(
5593                         DevicePolicyManager.WIFI_SECURITY_PERSONAL));
5594     }
5595 
5596     /**
5597      * Tests {@link WifiManager#notifyMinimumRequiredWifiSecurityLevelChanged(int)}
5598      * raise security exception without permission.
5599      */
5600     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testNotifyWifiSsidPolicyChangedWithoutPermission()5601     public void testNotifyWifiSsidPolicyChangedWithoutPermission() throws Exception {
5602         if (!WifiFeature.isWifiSupported(getContext())) {
5603             // skip the test if WiFi is not supported.
5604             return;
5605         }
5606         WifiSsidPolicy policy = new WifiSsidPolicy(
5607                 WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, new ArraySet<>(Arrays.asList(
5608                 WifiSsid.fromBytes("ssid".getBytes(StandardCharsets.UTF_8)))));
5609         try {
5610             mWifiManager.notifyWifiSsidPolicyChanged(policy);
5611             fail("Expected security exception due to lack of permission");
5612         } catch (SecurityException e) {
5613             // expected
5614         }
5615     }
5616 
5617     /**
5618      * Verifies that
5619      * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} raises
5620      * a security exception without permission.
5621      */
5622     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testIsItPossibleToCreateInterfaceNotAllowed()5623     public void testIsItPossibleToCreateInterfaceNotAllowed() throws Exception {
5624         if (!WifiFeature.isWifiSupported(getContext())) {
5625             // skip the test if WiFi is not supported
5626             return;
5627         }
5628 
5629         assertThrows(SecurityException.class, () -> mWifiManager.reportCreateInterfaceImpact(
5630                 WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor,
5631                 (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> {
5632                     // should not get here (security exception!)
5633                 }));
5634     }
5635 
5636     /**
5637      * Verifies
5638      * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} .
5639      */
5640     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testIsItPossibleToCreateInterface()5641     public void testIsItPossibleToCreateInterface() throws Exception {
5642         if (!WifiFeature.isWifiSupported(getContext())) {
5643             // skip the test if WiFi is not supported
5644             return;
5645         }
5646 
5647         AtomicBoolean called = new AtomicBoolean(false);
5648         AtomicBoolean canBeCreated = new AtomicBoolean(false);
5649         AtomicReference<Set<WifiManager.InterfaceCreationImpact>>
5650                 interfacesWhichWillBeDeleted = new AtomicReference<>(null);
5651         ShellIdentityUtils.invokeWithShellPermissions(
5652                 () -> mWifiManager.reportCreateInterfaceImpact(
5653                         WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor,
5654                         (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> {
5655                             synchronized (mLock) {
5656                                 canBeCreated.set(canBeCreatedLocal);
5657                                 called.set(true);
5658                                 interfacesWhichWillBeDeleted.set(interfacesWhichWillBeDeletedLocal);
5659                                 mLock.notify();
5660                             }
5661                         }));
5662         synchronized (mLock) {
5663             mLock.wait(TEST_WAIT_DURATION_MS);
5664         }
5665         assertTrue(called.get());
5666         if (canBeCreated.get()) {
5667             for (WifiManager.InterfaceCreationImpact entry : interfacesWhichWillBeDeleted.get()) {
5668                 int interfaceType = entry.getInterfaceType();
5669                 assertTrue(interfaceType == WifiManager.WIFI_INTERFACE_TYPE_STA
5670                         || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AP
5671                         || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_DIRECT
5672                         || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AWARE);
5673                 Set<String> packages = entry.getPackages();
5674                 for (String p : packages) {
5675                     assertNotNull(p);
5676                 }
5677             }
5678         }
5679 
5680         // verify the WifiManager.InterfaceCreationImpact APIs
5681         int interfaceType = WifiManager.WIFI_INTERFACE_TYPE_STA;
5682         Set<String> packages = Set.of("package1", "packages2");
5683         WifiManager.InterfaceCreationImpact element = new WifiManager.InterfaceCreationImpact(
5684                 interfaceType, packages);
5685         assertEquals(interfaceType, element.getInterfaceType());
5686         assertEquals(packages, element.getPackages());
5687     }
5688 
5689     /**
5690      * Tests {@link WifiManager#isEasyConnectDppAkmSupported)} does not crash.
5691      */
5692     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
testIsEasyConnectDppAkmSupported()5693     public void testIsEasyConnectDppAkmSupported() throws Exception {
5694         if (!WifiFeature.isWifiSupported(getContext())) {
5695             // skip the test if WiFi is not supported
5696             return;
5697         }
5698         mWifiManager.isEasyConnectDppAkmSupported();
5699     }
5700 }
5701