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.content.Context.RECEIVER_EXPORTED;
20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
21 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
22 import static android.net.wifi.SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
23 import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP;
24 import static android.net.wifi.WifiAvailableChannel.OP_MODE_STA;
25 import static android.net.wifi.WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO;
26 import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
27 import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP;
28 import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE;
29 import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT;
30 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
31 import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
32 import static android.os.Process.myUid;
33 
34 import static com.google.common.truth.Truth.assertThat;
35 import static com.google.common.truth.Truth.assertWithMessage;
36 
37 import static org.junit.Assert.assertArrayEquals;
38 import static org.junit.Assert.assertEquals;
39 import static org.junit.Assert.assertFalse;
40 import static org.junit.Assert.assertNotEquals;
41 import static org.junit.Assert.assertNotNull;
42 import static org.junit.Assert.assertNull;
43 import static org.junit.Assert.assertThrows;
44 import static org.junit.Assert.assertTrue;
45 import static org.junit.Assert.fail;
46 import static org.junit.Assume.assumeTrue;
47 
48 import android.annotation.NonNull;
49 import android.app.UiAutomation;
50 import android.app.admin.DevicePolicyManager;
51 import android.app.admin.WifiSsidPolicy;
52 import android.content.BroadcastReceiver;
53 import android.content.Context;
54 import android.content.Intent;
55 import android.content.IntentFilter;
56 import android.content.pm.PackageInfo;
57 import android.content.pm.PackageManager;
58 import android.content.pm.ResolveInfo;
59 import android.net.ConnectivityManager;
60 import android.net.MacAddress;
61 import android.net.Network;
62 import android.net.NetworkCapabilities;
63 import android.net.NetworkInfo;
64 import android.net.NetworkRequest;
65 import android.net.TetheringManager;
66 import android.net.Uri;
67 import android.net.wifi.CoexUnsafeChannel;
68 import android.net.wifi.MloLink;
69 import android.net.wifi.MscsParams;
70 import android.net.wifi.OuiKeyedData;
71 import android.net.wifi.QosCharacteristics;
72 import android.net.wifi.QosPolicyParams;
73 import android.net.wifi.ScanResult;
74 import android.net.wifi.SoftApCapability;
75 import android.net.wifi.SoftApConfiguration;
76 import android.net.wifi.SoftApInfo;
77 import android.net.wifi.SoftApState;
78 import android.net.wifi.UriParserResults;
79 import android.net.wifi.WifiAvailableChannel;
80 import android.net.wifi.WifiClient;
81 import android.net.wifi.WifiConfiguration;
82 import android.net.wifi.WifiEnterpriseConfig;
83 import android.net.wifi.WifiInfo;
84 import android.net.wifi.WifiManager;
85 import android.net.wifi.WifiManager.SubsystemRestartTrackingCallback;
86 import android.net.wifi.WifiManager.WifiLock;
87 import android.net.wifi.WifiNetworkConnectionStatistics;
88 import android.net.wifi.WifiNetworkSelectionConfig;
89 import android.net.wifi.WifiNetworkSuggestion;
90 import android.net.wifi.WifiScanner;
91 import android.net.wifi.WifiSsid;
92 import android.net.wifi.WifiUriParser;
93 import android.net.wifi.hotspot2.ConfigParser;
94 import android.net.wifi.hotspot2.OsuProvider;
95 import android.net.wifi.hotspot2.PasspointConfiguration;
96 import android.net.wifi.hotspot2.ProvisioningCallback;
97 import android.net.wifi.hotspot2.pps.Credential;
98 import android.net.wifi.hotspot2.pps.HomeSp;
99 import android.net.wifi.twt.TwtRequest;
100 import android.net.wifi.twt.TwtSession;
101 import android.net.wifi.twt.TwtSessionCallback;
102 import android.os.Build;
103 import android.os.Bundle;
104 import android.os.Handler;
105 import android.os.HandlerExecutor;
106 import android.os.HandlerThread;
107 import android.os.PersistableBundle;
108 import android.os.PowerManager;
109 import android.os.Process;
110 import android.os.SystemClock;
111 import android.os.SystemProperties;
112 import android.os.UserHandle;
113 import android.platform.test.annotations.AppModeFull;
114 import android.platform.test.annotations.AsbSecurityTest;
115 import android.platform.test.annotations.RequiresDevice;
116 import android.platform.test.annotations.RequiresFlagsEnabled;
117 import android.platform.test.flag.junit.CheckFlagsRule;
118 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
119 import android.provider.DeviceConfig;
120 import android.provider.Settings;
121 import android.support.test.uiautomator.UiDevice;
122 import android.telephony.TelephonyManager;
123 import android.text.TextUtils;
124 import android.util.ArraySet;
125 import android.util.Log;
126 import android.util.SparseArray;
127 import android.util.SparseIntArray;
128 
129 import androidx.test.ext.junit.runners.AndroidJUnit4;
130 import androidx.test.filters.SdkSuppress;
131 import androidx.test.platform.app.InstrumentationRegistry;
132 
133 import com.android.compatibility.common.util.ApiLevelUtil;
134 import com.android.compatibility.common.util.ApiTest;
135 import com.android.compatibility.common.util.FeatureUtil;
136 import com.android.compatibility.common.util.PollingCheck;
137 import com.android.compatibility.common.util.PropertyUtil;
138 import com.android.compatibility.common.util.ShellIdentityUtils;
139 import com.android.compatibility.common.util.SystemUtil;
140 import com.android.compatibility.common.util.ThrowingRunnable;
141 import com.android.modules.utils.build.SdkLevel;
142 import com.android.net.module.util.MacAddressUtils;
143 import com.android.wifi.flags.Flags;
144 
145 import com.google.common.collect.Range;
146 
147 import org.junit.AfterClass;
148 import org.junit.Before;
149 import org.junit.BeforeClass;
150 import org.junit.Rule;
151 import org.junit.Test;
152 import org.junit.runner.RunWith;
153 
154 import java.io.BufferedReader;
155 import java.io.IOException;
156 import java.io.InputStream;
157 import java.io.InputStreamReader;
158 import java.lang.reflect.Constructor;
159 import java.net.HttpURLConnection;
160 import java.net.InetAddress;
161 import java.net.URL;
162 import java.nio.charset.StandardCharsets;
163 import java.time.Duration;
164 import java.util.ArrayList;
165 import java.util.Arrays;
166 import java.util.Collections;
167 import java.util.HashMap;
168 import java.util.HashSet;
169 import java.util.List;
170 import java.util.Locale;
171 import java.util.Map;
172 import java.util.Objects;
173 import java.util.Set;
174 import java.util.concurrent.ConcurrentLinkedQueue;
175 import java.util.concurrent.CountDownLatch;
176 import java.util.concurrent.Executor;
177 import java.util.concurrent.Executors;
178 import java.util.concurrent.TimeUnit;
179 import java.util.concurrent.atomic.AtomicBoolean;
180 import java.util.concurrent.atomic.AtomicInteger;
181 import java.util.concurrent.atomic.AtomicReference;
182 import java.util.function.BiConsumer;
183 import java.util.function.Consumer;
184 import java.util.function.IntConsumer;
185 import java.util.stream.Collectors;
186 
187 @RunWith(AndroidJUnit4.class)
188 @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
189 public class WifiManagerTest extends WifiJUnit4TestBase {
190     private static Context sContext;
191     private static boolean sShouldRunTest = false;
192 
193     private static class MySync {
194         int expectedState = STATE_NULL;
195     }
196 
197     private static WifiManager sWifiManager;
198     private static ConnectivityManager sConnectivityManager;
199     private static TetheringManager sTetheringManager;
200     private static MySync sMySync;
201     private static List<ScanResult> sScanResults = null;
202     private static NetworkInfo sNetworkInfo =
203             new NetworkInfo(ConnectivityManager.TYPE_WIFI, TelephonyManager.NETWORK_TYPE_UNKNOWN,
204                     "wifi", "unknown");
205     private final Object mLock = new Object();
206     private static UiDevice sUiDevice;
207     private static boolean sWasVerboseLoggingEnabled;
208     private static boolean sWasScanThrottleEnabled;
209     private static SoftApConfiguration sOriginalSoftApConfig = null;
210     private static PowerManager sPowerManager;
211     private static PowerManager.WakeLock sWakeLock;
212     // Please refer to WifiManager
213     private static final int MIN_RSSI = -100;
214     private static final int MAX_RSSI = -55;
215 
216     private static final int STATE_NULL = 0;
217     private static final int STATE_WIFI_CHANGING = 1;
218     private static final int STATE_WIFI_ENABLED = 2;
219     private static final int STATE_WIFI_DISABLED = 3;
220     private static final int STATE_SCANNING = 4;
221     private static final int STATE_SCAN_DONE = 5;
222 
223     private static final String TAG = "WifiManagerTest";
224     private static final String SSID1 = "\"WifiManagerTest\"";
225     private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode";
226     // A full single scan duration is typically about 6-7 seconds, but
227     // depending on devices it takes more time (9-11 seconds). For a
228     // safety margin, the test waits for 15 seconds.
229     private static final int SCAN_TEST_WAIT_DURATION_MS = 15_000;
230     private static final int TEST_WAIT_DURATION_MS = 10_000;
231     private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000;
232     private static final int WIFI_OFF_ON_TIMEOUT_MILLIS = 5_000;
233     private static final int WIFI_PNO_CONNECT_TIMEOUT_MILLIS = 90_000;
234     private static final int WAIT_MSEC = 60;
235     private static final int DURATION_SCREEN_TOGGLE = 2000;
236     private static final int DURATION_SETTINGS_TOGGLE = 1_000;
237     private static final int DURATION_SOFTAP_START_MS = 6_000;
238     private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000;
239     private static final String DEVICE_CONFIG_NAMESPACE = "wifi";
240 
241     private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50;
242 
243     private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac";
244     private static final String MANAGED_PROVISIONING_PACKAGE_NAME
245             = "com.android.managedprovisioning";
246 
247     private static final String TEST_SSID_UNQUOTED = "testSsid1";
248     private static final String TEST_IP_ADDRESS = "192.168.5.5";
249     private static final String TEST_MAC_ADDRESS = "aa:bb:cc:dd:ee:ff";
250     private static final MacAddress TEST_MAC = MacAddress.fromString(TEST_MAC_ADDRESS);
251     private static final String TEST_PASSPHRASE = "passphrase";
252     private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT =
253             "assets/ValidPasspointProfile.base64";
254     private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config";
255     private static final String TEST_PSK_CAP = "[RSN-PSK-CCMP]";
256     private static final String TEST_BSSID = "00:01:02:03:04:05";
257     private static final String TEST_COUNTRY_CODE = "JP";
258     private static final String TEST_DOM_SUBJECT_MATCH = "domSubjectMatch";
259     private static final int TEST_SUB_ID = 2;
260     private static final int EID_VSA = 221; // Copied from ScanResult.InformationElement
261 
262     private static final int TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS = 1000;
263     private static final List<ScanResult.InformationElement> TEST_VENDOR_ELEMENTS =
264             new ArrayList<>(Arrays.asList(
265                     new ScanResult.InformationElement(221, 0, new byte[]{ 1, 2, 3, 4 }),
266                     new ScanResult.InformationElement(
267                             221,
268                             0,
269                             new byte[]{ (byte) 170, (byte) 187, (byte) 204, (byte) 221 })
270             ));
271     private static final int[] TEST_RSSI2_THRESHOLDS = {-81, -79, -73, -60};
272     private static final int[] TEST_RSSI5_THRESHOLDS = {-80, -77, -71, -55};
273     private static final int[] TEST_RSSI6_THRESHOLDS = {-79, -72, -65, -55};
274     private static final SparseArray<Integer> TEST_FREQUENCY_WEIGHTS = new SparseArray<>();
275 
276     private IntentFilter mIntentFilter;
277 
278     @Rule
279     public final CheckFlagsRule mCheckFlagsRule =
280             DeviceFlagsValueProvider.createCheckFlagsRule();
281     private static final BroadcastReceiver sReceiver = new BroadcastReceiver() {
282         @Override
283         public void onReceive(Context context, Intent intent) {
284             final String action = intent.getAction();
285             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
286                 synchronized (sMySync) {
287                     if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) {
288                         sScanResults = sWifiManager.getScanResults();
289                     } else {
290                         sScanResults = null;
291                     }
292                     sMySync.expectedState = STATE_SCAN_DONE;
293                     sMySync.notifyAll();
294                 }
295             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
296                 int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
297                         WifiManager.WIFI_STATE_UNKNOWN);
298                 synchronized (sMySync) {
299                     if (newState == WifiManager.WIFI_STATE_ENABLED) {
300                         Log.d(TAG, "*** New WiFi state is ENABLED ***");
301                         sMySync.expectedState = STATE_WIFI_ENABLED;
302                         sMySync.notifyAll();
303                     } else if (newState == WifiManager.WIFI_STATE_DISABLED) {
304                         Log.d(TAG, "*** New WiFi state is DISABLED ***");
305                         sMySync.expectedState = STATE_WIFI_DISABLED;
306                         sMySync.notifyAll();
307                     }
308                 }
309             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
310                 synchronized (sMySync) {
311                     sNetworkInfo =
312                             (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
313                     if (sNetworkInfo.getState() == NetworkInfo.State.CONNECTED) {
314                         sMySync.notifyAll();
315                     }
316                 }
317             }
318         }
319     };
320 
321     private static class TestProvisioningCallback extends ProvisioningCallback {
322         private final Object mObject;
323         // Initialize with an invalid status value (0)
324         public int mProvisioningStatus = 0;
325         // Initialize with an invalid status value (0)
326         public int mProvisioningFailureStatus = 0;
327         public boolean mProvisioningComplete = false;
328 
329 
TestProvisioningCallback(Object lock)330         TestProvisioningCallback(Object lock) {
331             mObject = lock;
332         }
333 
334         @Override
onProvisioningFailure(int status)335         public void onProvisioningFailure(int status) {
336             synchronized (mObject) {
337                 mProvisioningFailureStatus = status;
338                 mObject.notify();
339             }
340         }
341 
342         @Override
onProvisioningStatus(int status)343         public void onProvisioningStatus(int status) {
344             synchronized (mObject) {
345                 mProvisioningStatus = status;
346                 mObject.notify();
347             }
348         }
349 
350         @Override
onProvisioningComplete()351         public void onProvisioningComplete() {
352             mProvisioningComplete = true;
353         }
354     }
355 
356     private static class TestSubsystemRestartTrackingCallback
357             extends SubsystemRestartTrackingCallback {
358         private final Object mObject;
359 
360         public int mSubsystemRestartStatus = 0; // 0: nada, 1: restarting, 2: restarted
361 
TestSubsystemRestartTrackingCallback(Object lock)362         TestSubsystemRestartTrackingCallback(Object lock) {
363             mObject = lock;
364         }
365         @Override
onSubsystemRestarting()366         public void onSubsystemRestarting() {
367             synchronized (mObject) {
368                 mSubsystemRestartStatus = 1;
369                 mObject.notify();
370             }
371         }
372 
373         @Override
onSubsystemRestarted()374         public void onSubsystemRestarted() {
375             synchronized (mObject) {
376                 mSubsystemRestartStatus = 2;
377                 mObject.notify();
378 
379             }
380         }
381     }
382 
383     private static final String TEST_SSID = "TEST SSID";
384     private static final String TEST_FRIENDLY_NAME = "Friendly Name";
385     private static final Map<String, String> TEST_FRIENDLY_NAMES = new HashMap<>();
386     static {
387         TEST_FRIENDLY_NAMES.put("en", TEST_FRIENDLY_NAME);
388         TEST_FRIENDLY_NAMES.put("kr", TEST_FRIENDLY_NAME + 2);
389         TEST_FRIENDLY_NAMES.put("jp", TEST_FRIENDLY_NAME + 3);
390     }
391 
392     private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service";
393     private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com");
394     private static final String TEST_NAI = "test.access.com";
395     private static final List<Integer> TEST_METHOD_LIST =
396             Arrays.asList(1 /* METHOD_SOAP_XML_SPP */);
397     private final HandlerThread mHandlerThread = new HandlerThread("WifiManagerTest");
398     protected final Executor mExecutor;
399     {
mHandlerThread.start()400         mHandlerThread.start();
401         mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper()));
402     }
403 
404     /**
405      * Class which can be used to fetch an object out of a lambda. Fetching an object
406      * out of a local scope with HIDL is a common operation (although usually it can
407      * and should be avoided).
408      *
409      * @param <E> Inner object type.
410      */
411     public static final class Mutable<E> {
412         public E value;
413 
Mutable()414         public Mutable() {
415             value = null;
416         }
417 
Mutable(E value)418         public Mutable(E value) {
419             this.value = value;
420         }
421     }
422 
423     @BeforeClass
setUpClass()424     public static void setUpClass() throws Exception {
425         sContext = InstrumentationRegistry.getInstrumentation().getContext();
426         if (!WifiFeature.isWifiSupported(sContext)) {
427             // skip the test if WiFi is not supported
428             return;
429         }
430         sShouldRunTest = true;
431         sPowerManager = sContext.getSystemService(PowerManager.class);
432         sWakeLock = sPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
433         sMySync = new MySync();
434         IntentFilter intentFilter = new IntentFilter();
435         intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
436         intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
437         intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
438         intentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
439         intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
440         intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
441         intentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
442         intentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK);
443         intentFilter.setPriority(999);
444 
445         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
446             sContext.registerReceiver(sReceiver, intentFilter, RECEIVER_EXPORTED);
447         } else {
448             sContext.registerReceiver(sReceiver, intentFilter);
449         }
450         sWifiManager =  sContext.getSystemService(WifiManager.class);
451         sConnectivityManager = sContext.getSystemService(ConnectivityManager.class);
452         sTetheringManager = sContext.getSystemService(TetheringManager.class);
453         assertThat(sWifiManager).isNotNull();
454         assertThat(sTetheringManager).isNotNull();
455 
456         // turn on verbose logging for tests
457         sWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions(
458                 () -> sWifiManager.isVerboseLoggingEnabled());
459         ShellIdentityUtils.invokeWithShellPermissions(
460                 () -> sWifiManager.setVerboseLoggingEnabled(true));
461         // Disable scan throttling for tests.
462         sWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions(
463                 () -> sWifiManager.isScanThrottleEnabled());
464         ShellIdentityUtils.invokeWithShellPermissions(
465                 () -> sWifiManager.setScanThrottleEnabled(false));
466 
467         sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
468         turnScreenOnNoDelay();
469 
470         synchronized (sMySync) {
471             sMySync.expectedState = STATE_NULL;
472         }
473 
474         List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
475                 sWifiManager::getConfiguredNetworks);
476         assertThat(savedNetworks.isEmpty()).isFalse();
477 
478         // Get original config for restore
479         sOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions(
480                 sWifiManager::getSoftApConfiguration);
481     }
482 
483     @AfterClass
tearDownClass()484     public static void tearDownClass() throws Exception {
485         if (!sShouldRunTest) {
486             return;
487         }
488         if (!sWifiManager.isWifiEnabled()) {
489             setWifiEnabled(true);
490         }
491         sContext.unregisterReceiver(sReceiver);
492         ShellIdentityUtils.invokeWithShellPermissions(
493                 () -> sWifiManager.setScanThrottleEnabled(sWasScanThrottleEnabled));
494         ShellIdentityUtils.invokeWithShellPermissions(
495                 () -> sWifiManager.setVerboseLoggingEnabled(sWasVerboseLoggingEnabled));
496         // restore original softap config
497         ShellIdentityUtils.invokeWithShellPermissions(
498                 () -> sWifiManager.setSoftApConfiguration(sOriginalSoftApConfig));
499         Thread.sleep(TEST_WAIT_DURATION_MS);
500         if (sWakeLock.isHeld()) {
501             sWakeLock.release();
502         }
503     }
504 
505     @Before
setUp()506     public void setUp() throws Exception {
507         assumeTrue(sShouldRunTest);
508         // enable Wifi
509         if (!sWifiManager.isWifiEnabled()) {
510             setWifiEnabled(true);
511             startScan();
512         }
513         PollingCheck.check("Wifi not enabled", TEST_WAIT_DURATION_MS,
514                 () -> sWifiManager.isWifiEnabled());
515 
516         waitForConnection();
517     }
518 
setWifiEnabled(boolean enable)519     private static void setWifiEnabled(boolean enable) throws Exception {
520         synchronized (sMySync) {
521             if (sWifiManager.isWifiEnabled() != enable) {
522                 // the new state is different, we expect it to change
523                 sMySync.expectedState = STATE_WIFI_CHANGING;
524             } else {
525                 sMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
526             }
527             ShellIdentityUtils.invokeWithShellPermissions(
528                     () -> sWifiManager.setWifiEnabled(enable));
529             waitForExpectedWifiState(enable);
530         }
531     }
532 
waitForExpectedWifiState(boolean enabled)533     private static void waitForExpectedWifiState(boolean enabled) throws InterruptedException {
534         synchronized (sMySync) {
535             long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS;
536             int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
537             while (System.currentTimeMillis() < timeout
538                     && sMySync.expectedState != expected) {
539                 sMySync.wait(WAIT_MSEC);
540             }
541         }
542     }
543 
544     // Get the current scan status from sticky broadcast.
isScanCurrentlyAvailable()545     private boolean isScanCurrentlyAvailable() {
546         IntentFilter intentFilter = new IntentFilter();
547         intentFilter.addAction(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED);
548         Intent intent = sContext.registerReceiver(null, intentFilter);
549         assertNotNull(intent);
550         if (intent.getAction().equals(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED)) {
551             return intent.getBooleanExtra(WifiManager.EXTRA_SCAN_AVAILABLE, false);
552         }
553         return false;
554     }
555 
startScan()556     private void startScan() throws Exception {
557         synchronized (sMySync) {
558             sMySync.expectedState = STATE_SCANNING;
559             sScanResults = null;
560             assertTrue(sWifiManager.startScan());
561             long timeout = System.currentTimeMillis() + SCAN_TEST_WAIT_DURATION_MS;
562             while (System.currentTimeMillis() < timeout
563                     && sMySync.expectedState == STATE_SCANNING) {
564                 sMySync.wait(WAIT_MSEC);
565             }
566         }
567     }
568 
waitForNetworkInfoState(NetworkInfo.State state, int timeoutMillis)569     private void waitForNetworkInfoState(NetworkInfo.State state, int timeoutMillis)
570             throws Exception {
571         synchronized (sMySync) {
572             if (sNetworkInfo.getState() == state) return;
573             long timeout = System.currentTimeMillis() + timeoutMillis;
574             while (System.currentTimeMillis() < timeout
575                     && sNetworkInfo.getState() != state)
576                 sMySync.wait(WAIT_MSEC);
577             assertEquals(state, sNetworkInfo.getState());
578         }
579     }
580 
waitForConnection(int timeoutMillis)581     private void waitForConnection(int timeoutMillis) throws Exception {
582         waitForNetworkInfoState(NetworkInfo.State.CONNECTED, timeoutMillis);
583     }
584 
waitForConnection()585     private void waitForConnection() throws Exception {
586         waitForNetworkInfoState(NetworkInfo.State.CONNECTED, WIFI_CONNECT_TIMEOUT_MILLIS);
587     }
588 
waitForDisconnection()589     private void waitForDisconnection() throws Exception {
590         waitForNetworkInfoState(NetworkInfo.State.DISCONNECTED, TEST_WAIT_DURATION_MS);
591     }
592 
ensureNotNetworkInfoState(NetworkInfo.State state)593     private void ensureNotNetworkInfoState(NetworkInfo.State state) throws Exception {
594         synchronized (sMySync) {
595             long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS + WAIT_MSEC;
596             while (System.currentTimeMillis() < timeout) {
597                 assertNotEquals(state, sNetworkInfo.getState());
598                 sMySync.wait(WAIT_MSEC);
599             }
600         }
601     }
602 
ensureNotConnected()603     private void ensureNotConnected() throws Exception {
604         ensureNotNetworkInfoState(NetworkInfo.State.CONNECTED);
605     }
606 
ensureNotDisconnected()607     private void ensureNotDisconnected() throws Exception {
608         ensureNotNetworkInfoState(NetworkInfo.State.DISCONNECTED);
609     }
610 
existSSID(String ssid)611     private boolean existSSID(String ssid) {
612         for (final WifiConfiguration w : sWifiManager.getConfiguredNetworks()) {
613             if (w.SSID.equals(ssid))
614                 return true;
615         }
616         return false;
617     }
618 
findConfiguredNetworks(String SSID, List<WifiConfiguration> networks)619     private int findConfiguredNetworks(String SSID, List<WifiConfiguration> networks) {
620         for (final WifiConfiguration w : networks) {
621             if (w.SSID.equals(SSID))
622                 return networks.indexOf(w);
623         }
624         return -1;
625     }
626 
627     /**
628      * Test creation of WifiManager Lock.
629      */
630     @Test
testWifiManagerLock()631     public void testWifiManagerLock() throws Exception {
632         final String TAG = "Test";
633         assertNotNull(sWifiManager.createWifiLock(TAG));
634         assertNotNull(sWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG));
635     }
636 
637     /**
638      * Test wifi scanning when Wifi is off and location scanning is turned on.
639      */
640     @Test
testWifiManagerScanWhenWifiOffLocationTurnedOn()641     public void testWifiManagerScanWhenWifiOffLocationTurnedOn() throws Exception {
642         if (!hasLocationFeature()) {
643             Log.d(TAG, "Skipping test as location is not supported");
644             return;
645         }
646         if (!isLocationEnabled()) {
647             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
648                     + " empty when location is disabled!");
649         }
650         runWithScanning(() -> {
651             setWifiEnabled(false);
652             Thread.sleep(TEST_WAIT_DURATION_MS);
653             startScan();
654             if (sWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) {
655                 // Make sure at least one AP is found.
656                 assertNotNull("mScanResult should not be null!", sScanResults);
657                 assertFalse("empty scan results!", sScanResults.isEmpty());
658             } else {
659                 // Make sure no scan results are available.
660                 assertNull("mScanResult should be null!", sScanResults);
661             }
662             final String TAG = "Test";
663             assertNotNull(sWifiManager.createWifiLock(TAG));
664             assertNotNull(sWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG));
665         }, true /* run with enabled*/);
666     }
667 
668     /**
669      * Restart WiFi subsystem - verify that privileged call fails.
670      */
671     @Test
672     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testRestartWifiSubsystemShouldFailNoPermission()673     public void testRestartWifiSubsystemShouldFailNoPermission() throws Exception {
674         try {
675             sWifiManager.restartWifiSubsystem();
676             fail("The restartWifiSubsystem should not succeed - privileged call");
677         } catch (SecurityException e) {
678             // expected
679         }
680     }
681 
682     /**
683      * Restart WiFi subsystem and verify transition through states.
684      */
685     @Test
686     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
testRestartWifiSubsystem()687     public void testRestartWifiSubsystem() throws Exception {
688         TestSubsystemRestartTrackingCallback callback =
689                 new TestSubsystemRestartTrackingCallback(mLock);
690         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
691         try {
692             uiAutomation.adoptShellPermissionIdentity();
693             sWifiManager.registerSubsystemRestartTrackingCallback(mExecutor, callback);
694             synchronized (mLock) {
695                 sWifiManager.restartWifiSubsystem();
696                 mLock.wait(TEST_WAIT_DURATION_MS);
697             }
698             assertEquals(callback.mSubsystemRestartStatus, 1); // 1: restarting
699             waitForExpectedWifiState(false);
700             assertFalse(sWifiManager.isWifiEnabled());
701             synchronized (mLock) {
702                 mLock.wait(TEST_WAIT_DURATION_MS);
703                 assertEquals(callback.mSubsystemRestartStatus, 2); // 2: restarted
704             }
705             waitForExpectedWifiState(true);
706             assertTrue(sWifiManager.isWifiEnabled());
707         } finally {
708             // cleanup
709             sWifiManager.unregisterSubsystemRestartTrackingCallback(callback);
710             uiAutomation.dropShellPermissionIdentity();
711         }
712     }
713 
714     /**
715      * test point of wifiManager properties:
716      * 1.enable properties
717      * 2.DhcpInfo properties
718      * 3.wifi state
719      * 4.ConnectionInfo
720      */
721     @Test
testWifiManagerProperties()722     public void testWifiManagerProperties() throws Exception {
723         setWifiEnabled(true);
724         assertTrue(sWifiManager.isWifiEnabled());
725         assertNotNull(sWifiManager.getDhcpInfo());
726         assertEquals(WifiManager.WIFI_STATE_ENABLED, sWifiManager.getWifiState());
727         sWifiManager.getConnectionInfo();
728         setWifiEnabled(false);
729         assertFalse(sWifiManager.isWifiEnabled());
730     }
731 
732     /**
733      * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with
734      * {@link SystemClock#elapsedRealtime()} on device.<p>
735      * To run this test in cts-tradefed:
736      * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp
737      */
738     @Test
739     @RequiresDevice
testWifiScanTimestamp()740     public void testWifiScanTimestamp() throws Exception {
741         if (!hasLocationFeature()) {
742             Log.d(TAG, "Skipping test as location is not supported");
743             return;
744         }
745         if (!isLocationEnabled()) {
746             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
747                     + " empty when location is disabled!");
748         }
749         if (!sWifiManager.isWifiEnabled()) {
750             setWifiEnabled(true);
751         }
752         // Make sure the scan timestamps are consistent with the device timestamp within the range
753         // of WIFI_SCAN_TEST_CACHE_DELAY_MILLIS.
754         startScan();
755         // Make sure at least one AP is found.
756         assertTrue("mScanResult should not be null. This may be due to a scan timeout",
757                    sScanResults != null);
758         assertFalse("empty scan results!", sScanResults.isEmpty());
759         long nowMillis = SystemClock.elapsedRealtime();
760         // Keep track of how many APs are fresh in one scan.
761         int numFreshAps = 0;
762         for (ScanResult result : sScanResults) {
763             long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp);
764             if (Math.abs(nowMillis - scanTimeMillis)  < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) {
765                 numFreshAps++;
766             }
767         }
768         // At least half of the APs in the scan should be fresh.
769         int numTotalAps = sScanResults.size();
770         String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: "
771                 + numFreshAps;
772         assertTrue(msg, numFreshAps * 2 >= sScanResults.size());
773     }
774 
775     @Test
testConvertBetweenChannelFrequencyMhz()776     public void testConvertBetweenChannelFrequencyMhz() throws Exception {
777         int[] testFrequency_2G = {2412, 2437, 2462, 2484};
778         int[] testFrequency_5G = {5180, 5220, 5540, 5745};
779         int[] testFrequency_6G = {5955, 6435, 6535, 7115};
780         int[] testFrequency_60G = {58320, 64800};
781         SparseArray<int[]> testData = new SparseArray<>() {{
782             put(ScanResult.WIFI_BAND_24_GHZ, testFrequency_2G);
783             put(ScanResult.WIFI_BAND_5_GHZ, testFrequency_5G);
784             put(ScanResult.WIFI_BAND_6_GHZ, testFrequency_6G);
785             put(ScanResult.WIFI_BAND_60_GHZ, testFrequency_60G);
786         }};
787 
788         for (int i = 0; i < testData.size(); i++) {
789             for (int frequency : testData.valueAt(i)) {
790                 assertEquals(frequency, ScanResult.convertChannelToFrequencyMhzIfSupported(
791                       ScanResult.convertFrequencyMhzToChannelIfSupported(frequency), testData.keyAt(i)));
792             }
793         }
794     }
795 
796     // Return true if location is enabled.
isLocationEnabled()797     private boolean isLocationEnabled() {
798         return Settings.Secure.getInt(sContext.getContentResolver(),
799                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) !=
800                 Settings.Secure.LOCATION_MODE_OFF;
801     }
802 
803     // Returns true if the device has location feature.
hasLocationFeature()804     private boolean hasLocationFeature() {
805         return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION);
806     }
807 
hasAutomotiveFeature()808     private boolean hasAutomotiveFeature() {
809         return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
810     }
811 
hasWifiDirect()812     private boolean hasWifiDirect() {
813         return sContext.getPackageManager().hasSystemFeature(
814                 PackageManager.FEATURE_WIFI_DIRECT);
815     }
816 
hasWifiAware()817     private boolean hasWifiAware() {
818         return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
819     }
820 
821     @Test
testSignal()822     public void testSignal() {
823         final int numLevels = 9;
824         int expectLevel = 0;
825         assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels));
826         assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels));
827         expectLevel = 4;
828         assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2,
829                 numLevels));
830         int rssiA = 4;
831         int rssiB = 5;
832         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0);
833         rssiB = 4;
834         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0);
835         rssiA = 5;
836         rssiB = 4;
837         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0);
838     }
839 
840     /**
841      * Test that {@link WifiManager#calculateSignalLevel(int)} returns a value in the range
842      * [0, {@link WifiManager#getMaxSignalLevel()}], and its value is monotonically increasing as
843      * the RSSI increases.
844      */
845     @Test
testCalculateSignalLevel()846     public void testCalculateSignalLevel() {
847         int maxSignalLevel = sWifiManager.getMaxSignalLevel();
848 
849         int prevSignalLevel = 0;
850         for (int rssi = -150; rssi <= 50; rssi++) {
851             int signalLevel = sWifiManager.calculateSignalLevel(rssi);
852 
853             // between [0, maxSignalLevel]
854             assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(0);
855             assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtMost(maxSignalLevel);
856 
857             // calculateSignalLevel(rssi) <= calculateSignalLevel(rssi + 1)
858             assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(prevSignalLevel);
859             prevSignalLevel = signalLevel;
860         }
861     }
862 
863     public class TestWifiVerboseLoggingStatusChangedListener implements
864             WifiManager.WifiVerboseLoggingStatusChangedListener {
865         public int numCalls;
866         public boolean status;
867 
868         @Override
onWifiVerboseLoggingStatusChanged(boolean enabled)869         public void onWifiVerboseLoggingStatusChanged(boolean enabled) {
870             numCalls++;
871             status = enabled;
872         }
873     }
874 
875     public class TestSoftApCallback implements WifiManager.SoftApCallback {
876         final Object mSoftApLock;
877         SoftApState mCurrentSoftApState;
878         int currentState;
879         int currentFailureReason;
880         List<SoftApInfo> apInfoList = new ArrayList<>();
881         SoftApInfo apInfoOnSingleApMode;
882         Map<SoftApInfo, List<WifiClient>> apInfoClients = new HashMap<>();
883         List<WifiClient> currentClientList;
884         SoftApCapability currentSoftApCapability;
885         MacAddress lastBlockedClientMacAddress;
886         int lastBlockedClientReason;
887         boolean onStateChangedCalled = false;
888         boolean mOnSoftApStateChangedCalled = false;
889         boolean onSoftApCapabilityChangedCalled = false;
890         boolean onConnectedClientCalled = false;
891         boolean onConnectedClientChangedWithInfoCalled = false;
892         boolean onBlockedClientConnectingCalled = false;
893         int onSoftapInfoChangedCalledCount = 0;
894         int onSoftapInfoChangedWithListCalledCount = 0;
895 
TestSoftApCallback(Object lock)896         TestSoftApCallback(Object lock) {
897             mSoftApLock = lock;
898         }
899 
getOnStateChangedCalled()900         public boolean getOnStateChangedCalled() {
901             synchronized (mSoftApLock) {
902                 return onStateChangedCalled;
903             }
904         }
905 
906         /**
907          * Returns {@code true} if #onStateChanged(SoftApstate) was called, else {@code false}.
908          */
getOnSoftApStateChangedCalled()909         public boolean getOnSoftApStateChangedCalled() {
910             synchronized (mSoftApLock) {
911                 return mOnSoftApStateChangedCalled;
912             }
913         }
914 
getOnSoftapInfoChangedCalledCount()915         public int getOnSoftapInfoChangedCalledCount() {
916             synchronized (mSoftApLock) {
917                 return onSoftapInfoChangedCalledCount;
918             }
919         }
920 
getOnSoftApInfoChangedWithListCalledCount()921         public int getOnSoftApInfoChangedWithListCalledCount() {
922             synchronized (mSoftApLock) {
923                 return onSoftapInfoChangedWithListCalledCount;
924             }
925         }
926 
getOnSoftApCapabilityChangedCalled()927         public boolean getOnSoftApCapabilityChangedCalled() {
928             synchronized (mSoftApLock) {
929                 return onSoftApCapabilityChangedCalled;
930             }
931         }
932 
getOnConnectedClientChangedWithInfoCalled()933         public boolean getOnConnectedClientChangedWithInfoCalled() {
934             synchronized (mSoftApLock) {
935                 return onConnectedClientChangedWithInfoCalled;
936             }
937         }
938 
getOnConnectedClientCalled()939         public boolean getOnConnectedClientCalled() {
940             synchronized (mSoftApLock) {
941                 return onConnectedClientCalled;
942             }
943         }
944 
getOnBlockedClientConnectingCalled()945         public boolean getOnBlockedClientConnectingCalled() {
946             synchronized (mSoftApLock) {
947                 return onBlockedClientConnectingCalled;
948             }
949         }
950 
951         /**
952          * Returns the latest SoftApState passed into #onStateChanged(SoftApState).
953          */
getCurrentSoftApState()954         public SoftApState getCurrentSoftApState() {
955             synchronized (mSoftApLock) {
956                 return mCurrentSoftApState;
957             }
958         }
959 
getCurrentState()960         public int getCurrentState() {
961             synchronized (mSoftApLock) {
962                 return currentState;
963             }
964         }
965 
getCurrentStateFailureReason()966         public int getCurrentStateFailureReason() {
967             synchronized (mSoftApLock) {
968                 return currentFailureReason;
969             }
970         }
971 
getCurrentClientList()972         public List<WifiClient> getCurrentClientList() {
973             synchronized (mSoftApLock) {
974                 return new ArrayList<>(currentClientList);
975             }
976         }
977 
getCurrentSoftApInfo()978         public SoftApInfo getCurrentSoftApInfo() {
979             synchronized (mSoftApLock) {
980                 return apInfoOnSingleApMode;
981             }
982         }
983 
getCurrentSoftApInfoList()984         public List<SoftApInfo> getCurrentSoftApInfoList() {
985             synchronized (mSoftApLock) {
986                 return new ArrayList<>(apInfoList);
987             }
988         }
989 
getCurrentSoftApCapability()990         public SoftApCapability getCurrentSoftApCapability() {
991             synchronized (mSoftApLock) {
992                 return currentSoftApCapability;
993             }
994         }
995 
getLastBlockedClientMacAddress()996         public MacAddress getLastBlockedClientMacAddress() {
997             synchronized (mSoftApLock) {
998                 return lastBlockedClientMacAddress;
999             }
1000         }
1001 
getLastBlockedClientReason()1002         public int getLastBlockedClientReason() {
1003             synchronized (mSoftApLock) {
1004                 return lastBlockedClientReason;
1005             }
1006         }
1007 
1008         @Override
onStateChanged(int state, int failureReason)1009         public void onStateChanged(int state, int failureReason) {
1010             synchronized (mSoftApLock) {
1011                 currentState = state;
1012                 currentFailureReason = failureReason;
1013                 onStateChangedCalled = true;
1014             }
1015         }
1016 
1017         @Override
onStateChanged(SoftApState state)1018         public void onStateChanged(SoftApState state) {
1019             synchronized (mSoftApLock) {
1020                 mCurrentSoftApState = state;
1021                 mOnSoftApStateChangedCalled = true;
1022                 onStateChanged(state.getState(),
1023                         state.getState() == WIFI_AP_STATE_FAILED ? state.getFailureReason() : 0);
1024             }
1025         }
1026 
1027         @Override
onConnectedClientsChanged(List<WifiClient> clients)1028         public void onConnectedClientsChanged(List<WifiClient> clients) {
1029             synchronized (mSoftApLock) {
1030                 currentClientList = new ArrayList<>(clients);
1031                 onConnectedClientCalled = true;
1032             }
1033         }
1034 
1035         @Override
onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients)1036         public void onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients) {
1037             synchronized (mSoftApLock) {
1038                 apInfoClients.put(info, clients);
1039                 onConnectedClientChangedWithInfoCalled = true;
1040             }
1041         }
1042 
1043         @Override
onInfoChanged(List<SoftApInfo> infoList)1044         public void onInfoChanged(List<SoftApInfo> infoList) {
1045             synchronized (mSoftApLock) {
1046                 apInfoList = new ArrayList<>(infoList);
1047                 onSoftapInfoChangedWithListCalledCount++;
1048             }
1049         }
1050 
1051         @Override
onInfoChanged(SoftApInfo softApInfo)1052         public void onInfoChanged(SoftApInfo softApInfo) {
1053             synchronized (mSoftApLock) {
1054                 apInfoOnSingleApMode = softApInfo;
1055                 onSoftapInfoChangedCalledCount++;
1056             }
1057         }
1058 
1059         @Override
onCapabilityChanged(SoftApCapability softApCapability)1060         public void onCapabilityChanged(SoftApCapability softApCapability) {
1061             synchronized (mSoftApLock) {
1062                 currentSoftApCapability = softApCapability;
1063                 onSoftApCapabilityChangedCalled = true;
1064             }
1065         }
1066 
1067         @Override
onBlockedClientConnecting(WifiClient client, int blockedReason)1068         public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
1069             synchronized (mSoftApLock) {
1070                 lastBlockedClientMacAddress = client.getMacAddress();
1071                 lastBlockedClientReason = blockedReason;
1072                 onBlockedClientConnectingCalled = true;
1073             }
1074         }
1075     }
1076 
1077     private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback {
1078         Object hotspotLock;
1079         WifiManager.LocalOnlyHotspotReservation reservation = null;
1080         boolean onStartedCalled = false;
1081         boolean onStoppedCalled = false;
1082         boolean onFailedCalled = false;
1083         int failureReason = -1;
1084 
TestLocalOnlyHotspotCallback(Object lock)1085         TestLocalOnlyHotspotCallback(Object lock) {
1086             hotspotLock = lock;
1087         }
1088 
1089         @Override
onStarted(WifiManager.LocalOnlyHotspotReservation r)1090         public void onStarted(WifiManager.LocalOnlyHotspotReservation r) {
1091             synchronized (hotspotLock) {
1092                 reservation = r;
1093                 onStartedCalled = true;
1094                 hotspotLock.notify();
1095             }
1096         }
1097 
1098         @Override
onStopped()1099         public void onStopped() {
1100             synchronized (hotspotLock) {
1101                 onStoppedCalled = true;
1102                 hotspotLock.notify();
1103             }
1104         }
1105 
1106         @Override
onFailed(int reason)1107         public void onFailed(int reason) {
1108             synchronized (hotspotLock) {
1109                 onFailedCalled = true;
1110                 failureReason = reason;
1111                 hotspotLock.notify();
1112             }
1113         }
1114     }
1115 
getSupportedSoftApBand(SoftApCapability capability)1116     private List<Integer> getSupportedSoftApBand(SoftApCapability capability) {
1117         List<Integer> supportedApBands = new ArrayList<>();
1118         if (sWifiManager.is24GHzBandSupported() && capability.areFeaturesSupported(
1119                 SoftApCapability.SOFTAP_FEATURE_BAND_24G_SUPPORTED)) {
1120             supportedApBands.add(SoftApConfiguration.BAND_2GHZ);
1121         }
1122         if (sWifiManager.is5GHzBandSupported() && capability.areFeaturesSupported(
1123                 SoftApCapability.SOFTAP_FEATURE_BAND_5G_SUPPORTED)) {
1124             supportedApBands.add(SoftApConfiguration.BAND_5GHZ);
1125         }
1126         if (sWifiManager.is6GHzBandSupported() && capability.areFeaturesSupported(
1127                 SoftApCapability.SOFTAP_FEATURE_BAND_6G_SUPPORTED)) {
1128             supportedApBands.add(SoftApConfiguration.BAND_6GHZ);
1129         }
1130         if (sWifiManager.is60GHzBandSupported() && capability.areFeaturesSupported(
1131                 SoftApCapability.SOFTAP_FEATURE_BAND_60G_SUPPORTED)) {
1132             supportedApBands.add(SoftApConfiguration.BAND_60GHZ);
1133         }
1134         return supportedApBands;
1135     }
1136 
startLocalOnlyHotspot()1137     private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() {
1138         // Location mode must be enabled for this test
1139         if (!isLocationEnabled()) {
1140             fail("Please enable location for this test");
1141         }
1142 
1143         TestExecutor executor = new TestExecutor();
1144         TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock);
1145         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1146         List<Integer> supportedSoftApBands = new ArrayList<>();
1147         try {
1148             uiAutomation.adoptShellPermissionIdentity();
1149             verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback);
1150             supportedSoftApBands = getSupportedSoftApBand(
1151                     lohsSoftApCallback.getCurrentSoftApCapability());
1152         } catch (Exception ex) {
1153         } finally {
1154             // clean up
1155             unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback);
1156             uiAutomation.dropShellPermissionIdentity();
1157         }
1158         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
1159         synchronized (mLock) {
1160             try {
1161                 sWifiManager.startLocalOnlyHotspot(callback, null);
1162                 // now wait for callback
1163                 mLock.wait(TEST_WAIT_DURATION_MS);
1164             } catch (InterruptedException e) {
1165             }
1166             // check if we got the callback
1167             assertTrue(callback.onStartedCalled);
1168 
1169             SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
1170             assertNotNull(softApConfig);
1171             int securityType = softApConfig.getSecurityType();
1172             if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN
1173                     || securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
1174                     || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) {
1175                 assertNotNull(softApConfig.toWifiConfiguration());
1176             } else {
1177                 assertNull(softApConfig.toWifiConfiguration());
1178             }
1179             if (!hasAutomotiveFeature()) {
1180                 assertEquals(supportedSoftApBands.size() > 0 ? supportedSoftApBands.get(0)
1181                         : SoftApConfiguration.BAND_2GHZ,
1182                         callback.reservation.getSoftApConfiguration().getBand());
1183             }
1184             assertFalse(callback.onFailedCalled);
1185             assertFalse(callback.onStoppedCalled);
1186         }
1187         return callback;
1188     }
1189 
stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled)1190     private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) {
1191         synchronized (sMySync) {
1192             // we are expecting a new state
1193             sMySync.expectedState = STATE_WIFI_CHANGING;
1194 
1195             // now shut down LocalOnlyHotspot
1196             if (callback.reservation != null) {
1197                 callback.reservation.close();
1198             }
1199 
1200             try {
1201                 waitForExpectedWifiState(wifiEnabled);
1202             } catch (InterruptedException e) { }
1203         }
1204     }
1205 
1206     /**
1207      * Verify that calls to startLocalOnlyHotspot succeed with proper permissions.
1208      *
1209      * Note: Location mode must be enabled for this test.
1210      */
1211     @Test
testStartLocalOnlyHotspotSuccess()1212     public void testStartLocalOnlyHotspotSuccess() throws Exception {
1213         // check that softap mode is supported by the device
1214         if (!sWifiManager.isPortableHotspotSupported()) {
1215             return;
1216         }
1217         boolean wifiEnabled = sWifiManager.isWifiEnabled();
1218         if (wifiEnabled) {
1219             // Re-enabled Wi-Fi as shell for HalDeviceManager legacy LOHS behavior when there's
1220             // no STA+AP concurrency.
1221             ShellIdentityUtils.invokeWithShellPermissions(() ->
1222                     sWifiManager.setWifiEnabled(false));
1223             PollingCheck.check("Wifi turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
1224                     () -> !sWifiManager.isWifiEnabled());
1225             SystemUtil.runShellCommand("cmd wifi set-wifi-enabled enabled");
1226             PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
1227                     () -> sWifiManager.isWifiEnabled());
1228         }
1229         runWithScanning(() -> {
1230             TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
1231 
1232             // add sleep to avoid calling stopLocalOnlyHotspot before TetherController
1233             // initialization.
1234             // TODO: remove this sleep as soon as b/124330089 is fixed.
1235             Log.d(TAG, "Sleeping for 2 seconds");
1236             Thread.sleep(2000);
1237 
1238             stopLocalOnlyHotspot(callback, wifiEnabled);
1239 
1240             // wifi should either stay on, or come back on
1241             assertEquals(wifiEnabled, sWifiManager.isWifiEnabled());
1242         }, false);
1243     }
1244 
1245     /**
1246      * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK.
1247      */
1248     @Test
testDeprecatedApis()1249     public void testDeprecatedApis() throws Exception {
1250         WifiConfiguration wifiConfiguration = new WifiConfiguration();
1251         wifiConfiguration.SSID = SSID1;
1252         wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
1253 
1254         assertEquals(INVALID_NETWORK_ID,
1255                 sWifiManager.addNetwork(wifiConfiguration));
1256         assertEquals(INVALID_NETWORK_ID,
1257                 sWifiManager.updateNetwork(wifiConfiguration));
1258         assertFalse(sWifiManager.enableNetwork(0, true));
1259         assertFalse(sWifiManager.disableNetwork(0));
1260         assertFalse(sWifiManager.removeNetwork(0));
1261         assertFalse(sWifiManager.disconnect());
1262         assertFalse(sWifiManager.reconnect());
1263         assertFalse(sWifiManager.reassociate());
1264         assertTrue(sWifiManager.getConfiguredNetworks().isEmpty());
1265 
1266         boolean wifiEnabled = sWifiManager.isWifiEnabled();
1267         // now we should fail to toggle wifi state.
1268         assertFalse(sWifiManager.setWifiEnabled(!wifiEnabled));
1269         Thread.sleep(TEST_WAIT_DURATION_MS);
1270         assertEquals(wifiEnabled, sWifiManager.isWifiEnabled());
1271     }
1272 
1273     /**
1274      * Test the WifiManager APIs that return whether a feature is supported.
1275      */
1276     @Test
testGetSupportedFeatures()1277     public void testGetSupportedFeatures() {
1278         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
1279             // Skip the test if wifi module version is older than S.
1280             return;
1281         }
1282         sWifiManager.isMakeBeforeBreakWifiSwitchingSupported();
1283         sWifiManager.isStaBridgedApConcurrencySupported();
1284         sWifiManager.isDualBandSimultaneousSupported();
1285         sWifiManager.isTidToLinkMappingNegotiationSupported();
1286     }
1287 
1288     /**
1289      * Verify non DO apps cannot call removeNonCallerConfiguredNetworks.
1290      */
1291     @Test
testRemoveNonCallerConfiguredNetworksNotAllowed()1292     public void testRemoveNonCallerConfiguredNetworksNotAllowed() {
1293         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
1294             // Skip the test if wifi module version is older than S.
1295             return;
1296         }
1297         try {
1298             sWifiManager.removeNonCallerConfiguredNetworks();
1299             fail("Expected security exception for non DO app");
1300         } catch (SecurityException e) {
1301         }
1302     }
1303 
buildTestNetworkSelectionConfig()1304     private WifiNetworkSelectionConfig buildTestNetworkSelectionConfig() {
1305         TEST_FREQUENCY_WEIGHTS.put(2400, WifiNetworkSelectionConfig.FREQUENCY_WEIGHT_LOW);
1306         TEST_FREQUENCY_WEIGHTS.put(6000, WifiNetworkSelectionConfig.FREQUENCY_WEIGHT_HIGH);
1307 
1308         return new WifiNetworkSelectionConfig.Builder()
1309                 .setAssociatedNetworkSelectionOverride(
1310                         WifiNetworkSelectionConfig.ASSOCIATED_NETWORK_SELECTION_OVERRIDE_ENABLED)
1311                 .setSufficiencyCheckEnabledWhenScreenOff(false)
1312                 .setSufficiencyCheckEnabledWhenScreenOn(false)
1313                 .setUserConnectChoiceOverrideEnabled(false)
1314                 .setLastSelectionWeightEnabled(false)
1315                 .setRssiThresholds(ScanResult.WIFI_BAND_24_GHZ, TEST_RSSI2_THRESHOLDS)
1316                 .setRssiThresholds(ScanResult.WIFI_BAND_5_GHZ, TEST_RSSI5_THRESHOLDS)
1317                 .setRssiThresholds(ScanResult.WIFI_BAND_6_GHZ, TEST_RSSI6_THRESHOLDS)
1318                 .setFrequencyWeights(TEST_FREQUENCY_WEIGHTS)
1319                 .build();
1320     }
1321 
1322     /**
1323      * Verify the invalid and valid usages of {@code WifiManager#setNetworkSelectionConfig}.
1324      */
1325     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1326     @Test
testSetNetworkSelectionConfig()1327     public void testSetNetworkSelectionConfig() throws Exception {
1328         AtomicReference<WifiNetworkSelectionConfig> config = new AtomicReference<>();
1329         Consumer<WifiNetworkSelectionConfig> listener = new Consumer<WifiNetworkSelectionConfig>() {
1330             @Override
1331             public void accept(WifiNetworkSelectionConfig value) {
1332                 synchronized (mLock) {
1333                     config.set(value);
1334                     mLock.notify();
1335                 }
1336             }
1337         };
1338 
1339         // cache current WifiNetworkSelectionConfig
1340         ShellIdentityUtils.invokeWithShellPermissions(
1341                 () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener));
1342         synchronized (mLock) {
1343             mLock.wait(TEST_WAIT_DURATION_MS);
1344         }
1345         WifiNetworkSelectionConfig currentConfig = config.get();
1346 
1347         try {
1348             WifiNetworkSelectionConfig nsConfig = buildTestNetworkSelectionConfig();
1349             assertTrue(nsConfig.getAssociatedNetworkSelectionOverride()
1350                     == WifiNetworkSelectionConfig.ASSOCIATED_NETWORK_SELECTION_OVERRIDE_ENABLED);
1351             assertFalse(nsConfig.isSufficiencyCheckEnabledWhenScreenOff());
1352             assertFalse(nsConfig.isSufficiencyCheckEnabledWhenScreenOn());
1353             assertFalse(nsConfig.isUserConnectChoiceOverrideEnabled());
1354             assertFalse(nsConfig.isLastSelectionWeightEnabled());
1355             assertArrayEquals(TEST_RSSI2_THRESHOLDS,
1356                     nsConfig.getRssiThresholds(ScanResult.WIFI_BAND_24_GHZ));
1357             assertArrayEquals(TEST_RSSI5_THRESHOLDS,
1358                     nsConfig.getRssiThresholds(ScanResult.WIFI_BAND_5_GHZ));
1359             assertArrayEquals(TEST_RSSI6_THRESHOLDS,
1360                     nsConfig.getRssiThresholds(ScanResult.WIFI_BAND_6_GHZ));
1361             assertTrue(TEST_FREQUENCY_WEIGHTS.contentEquals(nsConfig.getFrequencyWeights()));
1362             assertThrows(SecurityException.class,
1363                     () -> sWifiManager.setNetworkSelectionConfig(nsConfig));
1364             ShellIdentityUtils.invokeWithShellPermissions(
1365                     () -> sWifiManager.setNetworkSelectionConfig(nsConfig));
1366             ShellIdentityUtils.invokeWithShellPermissions(
1367                     () -> sWifiManager.setNetworkSelectionConfig(
1368                             new WifiNetworkSelectionConfig.Builder().build()));
1369         } finally {
1370             // restore WifiNetworkSelectionConfig
1371             ShellIdentityUtils.invokeWithShellPermissions(
1372                     () -> sWifiManager.setNetworkSelectionConfig(currentConfig));
1373         }
1374     }
1375 
1376     /**
1377      * Verify the invalid and valid usages of {@code WifiManager#getNetworkSelectionConfig}.
1378      */
1379     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
1380     @Test
testGetNetworkSelectionConfig()1381     public void testGetNetworkSelectionConfig() throws Exception {
1382         AtomicReference<WifiNetworkSelectionConfig> config = new AtomicReference<>();
1383         Consumer<WifiNetworkSelectionConfig> listener = new Consumer<WifiNetworkSelectionConfig>() {
1384             @Override
1385             public void accept(WifiNetworkSelectionConfig value) {
1386                 synchronized (mLock) {
1387                     config.set(value);
1388                     mLock.notify();
1389                 }
1390             }
1391         };
1392 
1393         // cache current WifiNetworkSelectionConfig
1394         ShellIdentityUtils.invokeWithShellPermissions(
1395                 () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener));
1396         synchronized (mLock) {
1397             mLock.wait(TEST_WAIT_DURATION_MS);
1398         }
1399         WifiNetworkSelectionConfig currentConfig = config.get();
1400 
1401         try {
1402             // Test invalid inputs trigger IllegalArgumentException
1403             assertThrows("null executor should trigger exception", NullPointerException.class,
1404                     () -> sWifiManager.getNetworkSelectionConfig(null, listener));
1405             assertThrows("null listener should trigger exception", NullPointerException.class,
1406                     () -> sWifiManager.getNetworkSelectionConfig(mExecutor, null));
1407 
1408             // Test caller with no permission triggers SecurityException.
1409             assertThrows("No permission should trigger SecurityException", SecurityException.class,
1410                     () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener));
1411 
1412             // Test get/set WifiNetworkSelectionConfig
1413             WifiNetworkSelectionConfig nsConfig = buildTestNetworkSelectionConfig();
1414             ShellIdentityUtils.invokeWithShellPermissions(
1415                     () -> sWifiManager.setNetworkSelectionConfig(nsConfig));
1416             ShellIdentityUtils.invokeWithShellPermissions(
1417                     () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener));
1418             synchronized (mLock) {
1419                 mLock.wait(TEST_WAIT_DURATION_MS);
1420             }
1421             assertTrue(config.get().equals(nsConfig));
1422         } finally {
1423             // restore WifiNetworkSelectionConfig
1424             ShellIdentityUtils.invokeWithShellPermissions(
1425                     () -> sWifiManager.setNetworkSelectionConfig(currentConfig));
1426         }
1427     }
1428 
1429     /**
1430      * Verify setting the screen-on connectivity scan delay.
1431      */
1432     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1433     @Test
testSetOneShotScreenOnConnectivityScanDelayMillis()1434     public void testSetOneShotScreenOnConnectivityScanDelayMillis() {
1435         assertThrows(SecurityException.class,
1436                 () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(100));
1437         assertThrows(IllegalArgumentException.class, () -> {
1438             ShellIdentityUtils.invokeWithShellPermissions(
1439                     () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(-1));
1440         });
1441         ShellIdentityUtils.invokeWithShellPermissions(
1442                 () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(10000));
1443         ShellIdentityUtils.invokeWithShellPermissions(
1444                 () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(0));
1445     }
1446 
1447     /**
1448      * Verify setting the scan schedule.
1449      */
1450     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1451     @Test
testSetScreenOnScanSchedule()1452     public void testSetScreenOnScanSchedule() {
1453         List<WifiManager.ScreenOnScanSchedule> schedules = new ArrayList<>();
1454         schedules.add(new WifiManager.ScreenOnScanSchedule(Duration.ofSeconds(20),
1455                 WifiScanner.SCAN_TYPE_HIGH_ACCURACY));
1456         schedules.add(new WifiManager.ScreenOnScanSchedule(Duration.ofSeconds(40),
1457                 WifiScanner.SCAN_TYPE_LOW_LATENCY));
1458         assertEquals(20, schedules.get(0).getScanInterval().toSeconds());
1459         assertEquals(40, schedules.get(1).getScanInterval().toSeconds());
1460         assertEquals(WifiScanner.SCAN_TYPE_HIGH_ACCURACY, schedules.get(0).getScanType());
1461         assertEquals(WifiScanner.SCAN_TYPE_LOW_LATENCY, schedules.get(1).getScanType());
1462         ShellIdentityUtils.invokeWithShellPermissions(
1463                 () -> sWifiManager.setScreenOnScanSchedule(schedules));
1464         ShellIdentityUtils.invokeWithShellPermissions(
1465                 () -> sWifiManager.setScreenOnScanSchedule(null));
1466 
1467         // Creating an invalid ScanSchedule should throw an exception
1468         assertThrows(IllegalArgumentException.class, () -> new WifiManager.ScreenOnScanSchedule(
1469                 null, WifiScanner.SCAN_TYPE_HIGH_ACCURACY));
1470     }
1471 
1472     /**
1473      * Verify a normal app cannot set the scan schedule.
1474      */
1475     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1476     @Test
testSetScreenOnScanScheduleNoPermission()1477     public void testSetScreenOnScanScheduleNoPermission() {
1478         assertThrows(SecurityException.class, () -> sWifiManager.setScreenOnScanSchedule(null));
1479     }
1480 
1481     /**
1482      * Test coverage for the constructor of AddNetworkResult.
1483      */
1484     @Test
testAddNetworkResultCreation()1485     public void testAddNetworkResultCreation() {
1486         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
1487             // Skip the test if wifi module version is older than S.
1488             return;
1489         }
1490         int statusCode = WifiManager.AddNetworkResult.STATUS_NO_PERMISSION;
1491         int networkId = 5;
1492         WifiManager.AddNetworkResult result = new WifiManager.AddNetworkResult(
1493             statusCode, networkId);
1494         assertEquals("statusCode should match", statusCode, result.statusCode);
1495         assertEquals("networkId should match", networkId, result.networkId);
1496     }
1497 
1498     /**
1499      * Verify {@link WifiManager#setSsidsAllowlist(Set)} can be called with sufficient
1500      * privilege.
1501      */
1502     @Test
testGetAndSetSsidsAllowlist()1503     public void testGetAndSetSsidsAllowlist() {
1504         Set<WifiSsid> ssids = new ArraySet<>();
1505         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1506         ShellIdentityUtils.invokeWithShellPermissions(
1507                 () -> sWifiManager.setSsidsAllowlist(ssids));
1508 
1509         ShellIdentityUtils.invokeWithShellPermissions(
1510                 () -> assertEquals("Ssids should match", ssids,
1511                         sWifiManager.getSsidsAllowlist()));
1512 
1513         ShellIdentityUtils.invokeWithShellPermissions(
1514                 () -> sWifiManager.setSsidsAllowlist(Collections.EMPTY_SET));
1515         ShellIdentityUtils.invokeWithShellPermissions(
1516                 () -> assertEquals("Should equal to empty set",
1517                         Collections.EMPTY_SET,
1518                         sWifiManager.getSsidsAllowlist()));
1519 
1520         try {
1521             sWifiManager.setSsidsAllowlist(Collections.EMPTY_SET);
1522             fail("Expected SecurityException when called without permission");
1523         } catch (SecurityException e) {
1524             // expect the exception
1525         }
1526     }
1527 
1528     class TestPnoScanResultsCallback implements WifiManager.PnoScanResultsCallback {
1529         public CountDownLatch latch = new CountDownLatch(1);
1530         private boolean mRegisterSuccess;
1531         private int mRegisterFailedReason = -1;
1532         private int mRemovedReason = -1;
1533         private List<ScanResult> mScanResults;
1534 
1535         @Override
onScanResultsAvailable(List<ScanResult> scanResults)1536         public void onScanResultsAvailable(List<ScanResult> scanResults) {
1537             mScanResults = scanResults;
1538             latch.countDown();
1539         }
1540 
1541         @Override
onRegisterSuccess()1542         public void onRegisterSuccess() {
1543             mRegisterSuccess = true;
1544             latch.countDown();
1545         }
1546 
1547         @Override
onRegisterFailed(int reason)1548         public void onRegisterFailed(int reason) {
1549             mRegisterFailedReason = reason;
1550             latch.countDown();
1551         }
1552 
1553         @Override
onRemoved(int reason)1554         public void onRemoved(int reason) {
1555             mRemovedReason = reason;
1556             latch.countDown();
1557         }
1558 
isRegisterSuccess()1559         public boolean isRegisterSuccess() {
1560             return mRegisterSuccess;
1561         }
1562 
getRemovedReason()1563         public int getRemovedReason() {
1564             return mRemovedReason;
1565         }
1566 
getRegisterFailedReason()1567         public int getRegisterFailedReason() {
1568             return mRegisterFailedReason;
1569         }
1570 
getScanResults()1571         public List<ScanResult> getScanResults() {
1572             return mScanResults;
1573         }
1574     }
1575 
1576     /**
1577      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1578      * WifiManager.PnoScanResultsCallback)} can be called with proper permissions.
1579      */
1580     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1581     @Test
testSetExternalPnoScanRequestSuccess()1582     public void testSetExternalPnoScanRequestSuccess() throws Exception {
1583         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1584         List<WifiSsid> ssids = new ArrayList<>();
1585         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1586         int[] frequencies = new int[] {2412, 5180, 5805};
1587 
1588         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1589         ShellIdentityUtils.invokeWithShellPermissions(
1590                 () -> sWifiManager.setExternalPnoScanRequest(
1591                         ssids, frequencies, Executors.newSingleThreadExecutor(), callback));
1592 
1593         callback.latch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS);
1594         if (sWifiManager.isPreferredNetworkOffloadSupported()) {
1595             assertTrue("Expect register success or failed due to resource busy",
1596                     callback.isRegisterSuccess()
1597                     || callback.getRegisterFailedReason() == WifiManager.PnoScanResultsCallback
1598                             .REGISTER_PNO_CALLBACK_RESOURCE_BUSY);
1599         } else {
1600             assertEquals("Expect register fail due to not supported.",
1601                     WifiManager.PnoScanResultsCallback.REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED,
1602                     callback.getRegisterFailedReason());
1603         }
1604         sWifiManager.clearExternalPnoScanRequest();
1605     }
1606 
1607     /**
1608      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1609      * WifiManager.PnoScanResultsCallback)} can be called with null frequency.
1610      */
1611     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1612     @Test
testSetExternalPnoScanRequestSuccessNullFrequency()1613     public void testSetExternalPnoScanRequestSuccessNullFrequency() throws Exception {
1614         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1615         List<WifiSsid> ssids = new ArrayList<>();
1616         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1617 
1618         ShellIdentityUtils.invokeWithShellPermissions(
1619                 () -> sWifiManager.setExternalPnoScanRequest(
1620                         ssids, null, Executors.newSingleThreadExecutor(), callback));
1621         sWifiManager.clearExternalPnoScanRequest();
1622     }
1623 
1624     /**
1625      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1626      * WifiManager.PnoScanResultsCallback)} throws an Exception if called with too many SSIDs.
1627      */
1628     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1629     @Test
testSetExternalPnoScanRequestTooManySsidsException()1630     public void testSetExternalPnoScanRequestTooManySsidsException() throws Exception {
1631         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1632         List<WifiSsid> ssids = new ArrayList<>();
1633         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1634         ssids.add(WifiSsid.fromBytes("TEST_SSID_2".getBytes(StandardCharsets.UTF_8)));
1635         ssids.add(WifiSsid.fromBytes("TEST_SSID_3".getBytes(StandardCharsets.UTF_8)));
1636 
1637         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1638         assertThrows(IllegalArgumentException.class, () -> {
1639             ShellIdentityUtils.invokeWithShellPermissions(
1640                     () -> sWifiManager.setExternalPnoScanRequest(
1641                             ssids, null, Executors.newSingleThreadExecutor(), callback));
1642         });
1643     }
1644 
1645     /**
1646      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1647      * WifiManager.PnoScanResultsCallback)} throws an Exception if called with too many frequencies.
1648      */
1649     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1650     @Test
testSetExternalPnoScanRequestTooManyFrequenciesException()1651     public void testSetExternalPnoScanRequestTooManyFrequenciesException() throws Exception {
1652         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1653         List<WifiSsid> ssids = new ArrayList<>();
1654         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1655         int[] frequencies = new int[] {2412, 2417, 2422, 2427, 2432, 2437, 2447, 2452, 2457, 2462,
1656                 5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805};
1657 
1658         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1659         assertThrows(IllegalArgumentException.class, () -> {
1660             ShellIdentityUtils.invokeWithShellPermissions(
1661                     () -> sWifiManager.setExternalPnoScanRequest(
1662                             ssids, frequencies, Executors.newSingleThreadExecutor(), callback));
1663         });
1664     }
1665 
1666     /**
1667      * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
1668      * WifiManager.PnoScanResultsCallback)} cannot be called without permission.
1669      */
1670     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
1671     @Test
testSetExternalPnoScanRequestNoPermission()1672     public void testSetExternalPnoScanRequestNoPermission() throws Exception {
1673         TestExecutor executor = new TestExecutor();
1674         TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback();
1675         List<WifiSsid> ssids = new ArrayList<>();
1676         ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)));
1677 
1678         assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess());
1679         assertThrows(SecurityException.class,
1680                 () -> sWifiManager.setExternalPnoScanRequest(ssids, null, executor, callback));
1681     }
1682 
1683     /**
1684      * Verify the invalid and valid usages of {@code WifiManager#getLastCallerInfoForApi}.
1685      */
1686     @Test
testGetLastCallerInfoForApi()1687     public void testGetLastCallerInfoForApi() throws Exception {
1688         AtomicReference<String> packageName = new AtomicReference<>();
1689         AtomicBoolean enabled = new AtomicBoolean(false);
1690         BiConsumer<String, Boolean> listener = new BiConsumer<String, Boolean>() {
1691             @Override
1692             public void accept(String caller, Boolean value) {
1693                 synchronized (mLock) {
1694                     packageName.set(caller);
1695                     enabled.set(value);
1696                     mLock.notify();
1697                 }
1698             }
1699         };
1700         // Test invalid inputs trigger IllegalArgumentException
1701         assertThrows("Invalid apiType should trigger exception", IllegalArgumentException.class,
1702                 () -> sWifiManager.getLastCallerInfoForApi(-1, mExecutor, listener));
1703         assertThrows("null executor should trigger exception", IllegalArgumentException.class,
1704                 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP, null,
1705                         listener));
1706         assertThrows("null listener should trigger exception", IllegalArgumentException.class,
1707                 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP, mExecutor,
1708                         null));
1709 
1710         // Test caller with no permission triggers SecurityException.
1711         assertThrows("No permission should trigger SecurityException", SecurityException.class,
1712                 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP,
1713                         mExecutor, listener));
1714 
1715         String expectedPackage = "android.net.wifi.cts";
1716         boolean isEnabledBefore = sWifiManager.isWifiEnabled();
1717         // toggle wifi and verify getting last caller
1718         setWifiEnabled(!isEnabledBefore);
1719         ShellIdentityUtils.invokeWithShellPermissions(
1720                 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_WIFI_ENABLED, mExecutor,
1721                         listener));
1722         synchronized (mLock) {
1723             mLock.wait(TEST_WAIT_DURATION_MS);
1724         }
1725 
1726         assertEquals("package does not match", expectedPackage, packageName.get());
1727         assertEquals("enabled does not match", !isEnabledBefore, enabled.get());
1728 
1729         // toggle wifi again and verify last caller
1730         packageName.set(null);
1731         setWifiEnabled(isEnabledBefore);
1732         ShellIdentityUtils.invokeWithShellPermissions(
1733                 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_WIFI_ENABLED, mExecutor,
1734                         listener));
1735         synchronized (mLock) {
1736             mLock.wait(TEST_WAIT_DURATION_MS);
1737         }
1738         assertEquals("package does not match", expectedPackage, packageName.get());
1739         assertEquals("enabled does not match", isEnabledBefore, enabled.get());
1740     }
1741 
1742     /**
1743      * Verify that {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} throws a
1744      * SecurityException when called by a normal app.
1745      */
1746     @Test
testAddNetworkPrivilegedNotAllowedForNormalApps()1747     public void testAddNetworkPrivilegedNotAllowedForNormalApps() {
1748         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
1749             // Skip the test if wifi module version is older than S.
1750             return;
1751         }
1752         try {
1753             WifiConfiguration newOpenNetwork = new WifiConfiguration();
1754             newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\"";
1755             sWifiManager.addNetworkPrivileged(newOpenNetwork);
1756             fail("A normal app should not be able to call this API.");
1757         } catch (SecurityException e) {
1758         }
1759     }
1760 
1761     /**
1762      * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} throws an exception when
1763      * null is the input.
1764      */
1765     @Test
testAddNetworkPrivilegedBadInput()1766     public void testAddNetworkPrivilegedBadInput() {
1767         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
1768             // Skip the test if wifi module version is older than S.
1769             return;
1770         }
1771         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1772         try {
1773             uiAutomation.adoptShellPermissionIdentity();
1774             sWifiManager.addNetworkPrivileged(null);
1775             fail("Expected IllegalArgumentException");
1776         } catch (IllegalArgumentException e) {
1777         } finally {
1778             uiAutomation.dropShellPermissionIdentity();
1779         }
1780     }
1781 
1782     /**
1783      * Verify {@link WifiManager#getPrivilegedConnectedNetwork()} returns the currently
1784      * connected WifiConfiguration with randomized MAC address filtered out.
1785      */
1786     @Test
testGetPrivilegedConnectedNetworkSuccess()1787     public void testGetPrivilegedConnectedNetworkSuccess() throws Exception {
1788         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1789         try {
1790             uiAutomation.adoptShellPermissionIdentity();
1791             sWifiManager.startScan();
1792 
1793             WifiInfo wifiInfo = sWifiManager.getConnectionInfo();
1794             int curNetworkId = wifiInfo.getNetworkId();
1795             assertNotEquals("Should be connected to valid networkId", INVALID_NETWORK_ID,
1796                     curNetworkId);
1797             WifiConfiguration curConfig = sWifiManager.getPrivilegedConnectedNetwork();
1798             assertEquals("NetworkId should match", curNetworkId, curConfig.networkId);
1799             assertEquals("SSID should match", wifiInfo.getSSID(), curConfig.SSID);
1800             assertEquals("Randomized MAC should be filtered out", WifiInfo.DEFAULT_MAC_ADDRESS,
1801                     curConfig.getRandomizedMacAddress().toString());
1802         } finally {
1803             uiAutomation.dropShellPermissionIdentity();
1804         }
1805     }
1806 
1807     /**
1808      * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} works properly when the
1809      * calling app has permissions.
1810      */
1811     @Test
testAddNetworkPrivilegedSuccess()1812     public void testAddNetworkPrivilegedSuccess() {
1813         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
1814             // Skip the test if wifi module version is older than S.
1815             return;
1816         }
1817         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1818         WifiManager.AddNetworkResult result = null;
1819         try {
1820             uiAutomation.adoptShellPermissionIdentity();
1821             WifiConfiguration newOpenNetwork = new WifiConfiguration();
1822             newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\"";
1823             result = sWifiManager.addNetworkPrivileged(newOpenNetwork);
1824             assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
1825             assertTrue(result.networkId >= 0);
1826             List<WifiConfiguration> configuredNetworks = sWifiManager.getConfiguredNetworks();
1827             boolean found = false;
1828             for (WifiConfiguration config : configuredNetworks) {
1829                 if (config.networkId == result.networkId
1830                         && config.SSID.equals(newOpenNetwork.SSID)) {
1831                     found = true;
1832                     break;
1833                 }
1834             }
1835             assertTrue("addNetworkPrivileged returns success"
1836                     + "but the network is not found in getConfiguredNetworks", found);
1837 
1838             List<WifiConfiguration> privilegedConfiguredNetworks =
1839                     sWifiManager.getPrivilegedConfiguredNetworks();
1840             found = false;
1841             for (WifiConfiguration config : privilegedConfiguredNetworks) {
1842                 if (config.networkId == result.networkId
1843                         && config.SSID.equals(newOpenNetwork.SSID)) {
1844                     found = true;
1845                     break;
1846                 }
1847             }
1848             assertTrue("addNetworkPrivileged returns success"
1849                     + "but the network is not found in getPrivilegedConfiguredNetworks", found);
1850 
1851             List<WifiConfiguration> callerConfiguredNetworks =
1852                     sWifiManager.getCallerConfiguredNetworks();
1853             found = false;
1854             for (WifiConfiguration config : callerConfiguredNetworks) {
1855                 if (config.networkId == result.networkId
1856                         && config.SSID.equals(newOpenNetwork.SSID)) {
1857                     found = true;
1858                     break;
1859                 }
1860             }
1861             assertTrue("addNetworkPrivileged returns success"
1862                     + "but the network is not found in getCallerConfiguredNetworks", found);
1863         } finally {
1864             if (null != result) {
1865                 sWifiManager.removeNetwork(result.networkId);
1866             }
1867             uiAutomation.dropShellPermissionIdentity();
1868         }
1869     }
1870 
createConfig( String ssid, int type)1871     private WifiConfiguration createConfig(
1872             String ssid, int type) {
1873         WifiConfiguration config = new WifiConfiguration();
1874         config.SSID = "\"" + ssid + "\"";
1875         config.setSecurityParams(type);
1876         // set necessary fields for different types.
1877         switch (type) {
1878             case WifiConfiguration.SECURITY_TYPE_OPEN:
1879             case WifiConfiguration.SECURITY_TYPE_OWE:
1880                 break;
1881             case WifiConfiguration.SECURITY_TYPE_PSK:
1882             case WifiConfiguration.SECURITY_TYPE_SAE:
1883                 config.preSharedKey = "\"1qaz@WSX\"";
1884                 break;
1885             case WifiConfiguration.SECURITY_TYPE_EAP:
1886             case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
1887             case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
1888                 config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
1889                 break;
1890         }
1891         return config;
1892     }
1893 
assertConfigsAreFound( List<WifiConfiguration> expectedConfigs, List<WifiConfiguration> configs)1894     private void assertConfigsAreFound(
1895             List<WifiConfiguration> expectedConfigs,
1896             List<WifiConfiguration> configs) {
1897         for (WifiConfiguration expectedConfig: expectedConfigs) {
1898             boolean found = false;
1899             for (WifiConfiguration config : configs) {
1900                 if (config.networkId == expectedConfig.networkId
1901                         && config.getKey().equals(expectedConfig.getKey())) {
1902                     found = true;
1903                     break;
1904                 }
1905             }
1906             assertTrue("the network " + expectedConfig.getKey() + " is not found", found);
1907         }
1908     }
1909 
1910     /**
1911      * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} works
1912      * with merging types properly when the calling app has permissions.
1913      */
1914     @Test
testAddNetworkPrivilegedMergingTypeSuccess()1915     public void testAddNetworkPrivilegedMergingTypeSuccess() {
1916         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
1917             // Skip the test if wifi module version is older than S.
1918             return;
1919         }
1920         List<WifiConfiguration> baseConfigs = new ArrayList<>();
1921         baseConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OPEN));
1922         baseConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_PSK));
1923         baseConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
1924                 WifiConfiguration.SECURITY_TYPE_EAP));
1925         List<WifiConfiguration> upgradeConfigs = new ArrayList<>();
1926         upgradeConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OWE));
1927         upgradeConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_SAE));
1928         upgradeConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
1929                 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
1930         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
1931         try {
1932             uiAutomation.adoptShellPermissionIdentity();
1933             final int originalConfiguredNetworksNumber =
1934                     sWifiManager.getConfiguredNetworks().size();
1935             final int originalPrivilegedConfiguredNetworksNumber =
1936                     sWifiManager.getPrivilegedConfiguredNetworks().size();
1937             final int originalCallerConfiguredNetworksNumber =
1938                     sWifiManager.getCallerConfiguredNetworks().size();
1939             for (WifiConfiguration c: baseConfigs) {
1940                 WifiManager.AddNetworkResult result = sWifiManager.addNetworkPrivileged(c);
1941                 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
1942                 assertTrue(result.networkId >= 0);
1943                 c.networkId = result.networkId;
1944             }
1945             for (WifiConfiguration c: upgradeConfigs) {
1946                 WifiManager.AddNetworkResult result = sWifiManager.addNetworkPrivileged(c);
1947                 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
1948                 assertTrue(result.networkId >= 0);
1949                 c.networkId = result.networkId;
1950             }
1951             // open/owe, psk/sae, and wpa2e/wpa3e should be merged
1952             // so they should have the same network ID.
1953             for (int i = 0; i < baseConfigs.size(); i++) {
1954                 assertEquals(baseConfigs.get(i).networkId, upgradeConfigs.get(i).networkId);
1955             }
1956 
1957             int numAddedConfigs = baseConfigs.size();
1958             List<WifiConfiguration> expectedConfigs = new ArrayList<>(baseConfigs);
1959             if (SdkLevel.isAtLeastS()) {
1960                 // S devices and above will return one additional config per each security type
1961                 // added, so we include the number of both base and upgrade configs.
1962                 numAddedConfigs += upgradeConfigs.size();
1963                 expectedConfigs.addAll(upgradeConfigs);
1964             }
1965             List<WifiConfiguration> configuredNetworks = sWifiManager.getConfiguredNetworks();
1966             assertEquals(originalConfiguredNetworksNumber + numAddedConfigs,
1967                     configuredNetworks.size());
1968             assertConfigsAreFound(expectedConfigs, configuredNetworks);
1969 
1970             List<WifiConfiguration> privilegedConfiguredNetworks =
1971                     sWifiManager.getPrivilegedConfiguredNetworks();
1972             assertEquals(originalPrivilegedConfiguredNetworksNumber + numAddedConfigs,
1973                     privilegedConfiguredNetworks.size());
1974             assertConfigsAreFound(expectedConfigs, privilegedConfiguredNetworks);
1975 
1976             List<WifiConfiguration> callerConfiguredNetworks =
1977                     sWifiManager.getCallerConfiguredNetworks();
1978             assertEquals(originalCallerConfiguredNetworksNumber + numAddedConfigs,
1979                     callerConfiguredNetworks.size());
1980             assertConfigsAreFound(expectedConfigs, callerConfiguredNetworks);
1981 
1982         } finally {
1983             for (WifiConfiguration c: baseConfigs) {
1984                 if (c.networkId >= 0) {
1985                     sWifiManager.removeNetwork(c.networkId);
1986                 }
1987             }
1988             uiAutomation.dropShellPermissionIdentity();
1989         }
1990     }
1991 
1992     /**
1993      * Verify that applications can only have one registered LocalOnlyHotspot request at a time.
1994      *
1995      * Note: Location mode must be enabled for this test.
1996      */
1997     @Test
testStartLocalOnlyHotspotSingleRequestByApps()1998     public void testStartLocalOnlyHotspotSingleRequestByApps() throws Exception {
1999         // check that softap mode is supported by the device
2000         assumeTrue(sWifiManager.isPortableHotspotSupported());
2001         boolean wifiEnabled = sWifiManager.isWifiEnabled();
2002         if (wifiEnabled) {
2003             // Re-enabled Wi-Fi as shell for HalDeviceManager legacy LOHS behavior when there's
2004             // no STA+AP concurrency.
2005             ShellIdentityUtils.invokeWithShellPermissions(() ->
2006                     sWifiManager.setWifiEnabled(false));
2007             PollingCheck.check("Wifi turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
2008                     () -> !sWifiManager.isWifiEnabled());
2009             SystemUtil.runShellCommand("cmd wifi set-wifi-enabled enabled");
2010             PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
2011                     () -> sWifiManager.isWifiEnabled());
2012         }
2013 
2014         runWithScanning(() -> {
2015             boolean caughtException = false;
2016             TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
2017 
2018             // now make a second request - this should fail.
2019             TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLock);
2020             try {
2021                 sWifiManager.startLocalOnlyHotspot(callback2, null);
2022             } catch (IllegalStateException e) {
2023                 Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice");
2024                 caughtException = true;
2025             }
2026             if (!caughtException) {
2027                 // second start did not fail, should clean up the hotspot.
2028 
2029                 // add sleep to avoid calling stopLocalOnlyHotspot before TetherController
2030                 // initialization.
2031                 // TODO: remove this sleep as soon as b/124330089 is fixed.
2032                 Log.d(TAG, "Sleeping for 2 seconds");
2033                 Thread.sleep(2000);
2034 
2035                 stopLocalOnlyHotspot(callback2, wifiEnabled);
2036             }
2037             assertTrue(caughtException);
2038 
2039             // add sleep to avoid calling stopLocalOnlyHotspot before TetherController
2040             // initialization.
2041             // TODO: remove this sleep as soon as b/124330089 is fixed.
2042             Log.d(TAG, "Sleeping for 2 seconds");
2043             Thread.sleep(2000);
2044 
2045             stopLocalOnlyHotspot(callback, wifiEnabled);
2046         }, false);
2047     }
2048 
2049     private static class TestExecutor implements Executor {
2050         private ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>();
2051 
2052         @Override
execute(Runnable task)2053         public void execute(Runnable task) {
2054             tasks.add(task);
2055         }
2056 
runAll()2057         private void runAll() {
2058             Runnable task = tasks.poll();
2059             while (task != null) {
2060                 task.run();
2061                 task = tasks.poll();
2062             }
2063         }
2064     }
2065 
generateSoftApConfigBuilderWithSsid(String ssid)2066     private SoftApConfiguration.Builder generateSoftApConfigBuilderWithSsid(String ssid) {
2067         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2068             return new SoftApConfiguration.Builder().setWifiSsid(
2069                     WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8)));
2070         }
2071         return new SoftApConfiguration.Builder().setSsid(ssid);
2072     }
2073 
assertSsidEquals(SoftApConfiguration config, String expectedSsid)2074     private void assertSsidEquals(SoftApConfiguration config, String expectedSsid) {
2075         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2076             assertEquals(WifiSsid.fromBytes(expectedSsid.getBytes(StandardCharsets.UTF_8)),
2077                     config.getWifiSsid());
2078         } else {
2079             assertEquals(expectedSsid, config.getSsid());
2080         }
2081     }
2082 
unregisterLocalOnlyHotspotSoftApCallback(TestSoftApCallback lohsSoftApCallback)2083     private void unregisterLocalOnlyHotspotSoftApCallback(TestSoftApCallback lohsSoftApCallback) {
2084         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2085             sWifiManager.unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback);
2086         } else {
2087             sWifiManager.unregisterSoftApCallback(lohsSoftApCallback);
2088         }
2089     }
2090 
2091     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
2092     @Test
testStartLocalOnlyHotspotWithSupportedBand()2093     public void testStartLocalOnlyHotspotWithSupportedBand() throws Exception {
2094         // check that softap mode is supported by the device
2095         if (!sWifiManager.isPortableHotspotSupported()) {
2096             return;
2097         }
2098 
2099         TestExecutor executor = new TestExecutor();
2100         TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock);
2101         setWifiEnabled(false);
2102         Thread.sleep(TEST_WAIT_DURATION_MS);
2103         boolean wifiEnabled = sWifiManager.isWifiEnabled();
2104         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2105         try {
2106             uiAutomation.adoptShellPermissionIdentity();
2107             verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback);
2108             SoftApConfiguration.Builder customConfigBuilder =
2109                     generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
2110                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
2111 
2112             SparseIntArray testBandsAndChannels = getAvailableBandAndChannelForTesting(
2113                     lohsSoftApCallback.getCurrentSoftApCapability());
2114             // The devices which doesn't have SIM and default country code in system property
2115             // (ro.boot.wificountrycodeCountry) will return a null country code. Since country code
2116             // is mandatory for 5GHz/6GHz band, skip the softap operation on 5GHz & 6GHz only band.
2117             boolean skip5g6gBand = false;
2118             String wifiCountryCode = ShellIdentityUtils.invokeWithShellPermissions(
2119                     sWifiManager::getCountryCode);
2120             if (wifiCountryCode == null) {
2121                 skip5g6gBand = true;
2122                 Log.e(TAG, "Country Code is not available - Skip 5GHz and 6GHz test");
2123             }
2124             for (int i = 0; i < testBandsAndChannels.size(); i++) {
2125                 TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
2126                 int testBand = testBandsAndChannels.keyAt(i);
2127                 if (skip5g6gBand && (testBand == SoftApConfiguration.BAND_6GHZ
2128                         || testBand == SoftApConfiguration.BAND_5GHZ)) {
2129                     continue;
2130                 }
2131                 // WPA2_PSK is not allowed in 6GHz band. So test with WPA3_SAE which is
2132                 // mandatory to support in 6GHz band.
2133                 if (testBand == SoftApConfiguration.BAND_6GHZ) {
2134                     if (lohsSoftApCallback.getCurrentSoftApCapability()
2135                             .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) {
2136                         customConfigBuilder.setPassphrase(TEST_PASSPHRASE,
2137                             SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
2138                     } else {
2139                         Log.e(TAG, "SoftAp 6GHz capability is advertized without WPA3 support");
2140                         continue;
2141                     }
2142                 }
2143                 customConfigBuilder.setBand(testBand);
2144                 sWifiManager.startLocalOnlyHotspot(customConfigBuilder.build(), executor, callback);
2145                 // now wait for callback
2146                 Thread.sleep(DURATION_SOFTAP_START_MS);
2147 
2148                 // Verify callback is run on the supplied executor
2149                 assertFalse(callback.onStartedCalled);
2150                 executor.runAll();
2151                 assertTrue(callback.onStartedCalled);
2152                 assertNotNull(callback.reservation);
2153                 SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
2154                 assertEquals(
2155                         WifiSsid.fromBytes(TEST_SSID_UNQUOTED.getBytes(StandardCharsets.UTF_8)),
2156                         softApConfig.getWifiSsid());
2157                 assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
2158                 // Automotive mode can force the LOHS to specific bands
2159                 if (!hasAutomotiveFeature()) {
2160                     assertEquals(testBand, softApConfig.getBand());
2161                 }
2162                 if (lohsSoftApCallback.getOnSoftapInfoChangedCalledCount() > 1) {
2163                     assertTrue(lohsSoftApCallback.getCurrentSoftApInfo().getFrequency() > 0);
2164                 }
2165                 stopLocalOnlyHotspot(callback, wifiEnabled);
2166             }
2167         } finally {
2168             // clean up
2169             sWifiManager.unregisterSoftApCallback(lohsSoftApCallback);
2170             uiAutomation.dropShellPermissionIdentity();
2171         }
2172     }
2173 
2174     @Test
testStartLocalOnlyHotspotWithConfigBssid()2175     public void testStartLocalOnlyHotspotWithConfigBssid() throws Exception {
2176         // check that softap mode is supported by the device
2177         if (!sWifiManager.isPortableHotspotSupported()) {
2178             return;
2179         }
2180 
2181         TestExecutor executor = new TestExecutor();
2182         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
2183         TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock);
2184         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2185         boolean wifiEnabled = sWifiManager.isWifiEnabled();
2186         try {
2187             uiAutomation.adoptShellPermissionIdentity();
2188             verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback);
2189             SoftApConfiguration.Builder customConfigBuilder =
2190                     generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
2191                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
2192 
2193             boolean isSupportCustomizedMac = lohsSoftApCallback.getCurrentSoftApCapability()
2194                         .areFeaturesSupported(
2195                         SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION)
2196                     && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S);
2197             if (isSupportCustomizedMac) {
2198                 customConfigBuilder.setBssid(TEST_MAC).setMacRandomizationSetting(
2199                             SoftApConfiguration.RANDOMIZATION_NONE);
2200             }
2201             SoftApConfiguration customConfig = customConfigBuilder.build();
2202 
2203             sWifiManager.startLocalOnlyHotspot(customConfig, executor, callback);
2204             // now wait for callback
2205             Thread.sleep(TEST_WAIT_DURATION_MS);
2206 
2207             // Verify callback is run on the supplied executor
2208             assertFalse(callback.onStartedCalled);
2209             executor.runAll();
2210             assertTrue(callback.onStartedCalled);
2211 
2212             assertNotNull(callback.reservation);
2213             SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
2214             assertNotNull(softApConfig);
2215             if (isSupportCustomizedMac) {
2216                 assertEquals(TEST_MAC, softApConfig.getBssid());
2217             }
2218             assertSsidEquals(softApConfig, TEST_SSID_UNQUOTED);
2219             assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
2220         } finally {
2221             // clean up
2222             stopLocalOnlyHotspot(callback, wifiEnabled);
2223             unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback);
2224             uiAutomation.dropShellPermissionIdentity();
2225         }
2226     }
2227 
2228     @Test
testStartLocalOnlyHotspotWithNullBssidConfig()2229     public void testStartLocalOnlyHotspotWithNullBssidConfig() throws Exception {
2230         // check that softap mode is supported by the device
2231         if (!sWifiManager.isPortableHotspotSupported()) {
2232             return;
2233         }
2234         SoftApConfiguration customConfig =
2235                 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
2236                 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
2237                 .build();
2238 
2239         TestExecutor executor = new TestExecutor();
2240         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
2241         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2242         boolean wifiEnabled = sWifiManager.isWifiEnabled();
2243         try {
2244             uiAutomation.adoptShellPermissionIdentity();
2245 
2246             sWifiManager.startLocalOnlyHotspot(customConfig, executor, callback);
2247             // now wait for callback
2248             Thread.sleep(TEST_WAIT_DURATION_MS);
2249 
2250             // Verify callback is run on the supplied executor
2251             assertFalse(callback.onStartedCalled);
2252             executor.runAll();
2253             assertTrue(callback.onStartedCalled);
2254 
2255             assertNotNull(callback.reservation);
2256             SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
2257             assertNotNull(softApConfig);
2258             assertSsidEquals(softApConfig, TEST_SSID_UNQUOTED);
2259             assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
2260         } finally {
2261             // clean up
2262             stopLocalOnlyHotspot(callback, wifiEnabled);
2263             uiAutomation.dropShellPermissionIdentity();
2264         }
2265     }
2266 
2267     /**
2268      * Read the content of the given resource file into a String.
2269      *
2270      * @param filename String name of the file
2271      * @return String
2272      * @throws IOException
2273      */
loadResourceFile(String filename)2274     private String loadResourceFile(String filename) throws IOException {
2275         InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
2276         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
2277         StringBuilder builder = new StringBuilder();
2278         String line;
2279         while ((line = reader.readLine()) != null) {
2280             builder.append(line).append("\n");
2281         }
2282         return builder.toString();
2283     }
2284 
2285     /**
2286      * Verify that changing the mac randomization setting of a Passpoint configuration.
2287      */
2288     @Test
testMacRandomizationSettingPasspoint()2289     public void testMacRandomizationSettingPasspoint() throws Exception {
2290         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
2291         PasspointConfiguration config =
2292                 ConfigParser.parsePasspointConfig(TYPE_WIFI_CONFIG, configStr.getBytes());
2293         String fqdn = config.getHomeSp().getFqdn();
2294         String uniqueId = config.getUniqueId();
2295         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2296         try {
2297             uiAutomation.adoptShellPermissionIdentity();
2298 
2299             sWifiManager.addOrUpdatePasspointConfiguration(config);
2300             PasspointConfiguration passpointConfig = getTargetPasspointConfiguration(
2301                     sWifiManager.getPasspointConfigurations(), uniqueId);
2302             assertNotNull("The installed passpoint profile is missing", passpointConfig);
2303             assertTrue("Mac randomization should be enabled for passpoint networks by default.",
2304                     passpointConfig.isMacRandomizationEnabled());
2305 
2306             sWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, false);
2307             passpointConfig = getTargetPasspointConfiguration(
2308                     sWifiManager.getPasspointConfigurations(), uniqueId);
2309             assertNotNull("The installed passpoint profile is missing", passpointConfig);
2310             assertFalse("Mac randomization should be disabled by the API call.",
2311                     passpointConfig.isMacRandomizationEnabled());
2312         } finally {
2313             // Clean up
2314             sWifiManager.removePasspointConfiguration(fqdn);
2315             uiAutomation.dropShellPermissionIdentity();
2316         }
2317     }
2318     /**
2319      * Verify that the {@link android.Manifest.permission#NETWORK_STACK} permission is never held by
2320      * any package.
2321      * <p>
2322      * No apps should <em>ever</em> attempt to acquire this permission, since it would give those
2323      * apps extremely broad access to connectivity functionality.
2324      */
2325     @Test
testNetworkStackPermission()2326     public void testNetworkStackPermission() {
2327         final PackageManager pm = sContext.getPackageManager();
2328 
2329         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2330                 android.Manifest.permission.NETWORK_STACK
2331         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2332         for (PackageInfo pi : holding) {
2333             fail("The NETWORK_STACK permission must not be held by " + pi.packageName
2334                     + " and must be revoked for security reasons");
2335         }
2336     }
2337 
2338     /**
2339      * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is
2340      * never held by any package.
2341      * <p>
2342      * Only Settings, SysUi, NetworkStack and shell apps should <em>ever</em> attempt to acquire
2343      * this permission, since it would give those apps extremely broad access to connectivity
2344      * functionality.  The permission is intended to be granted to only those apps with direct user
2345      * access and no others.
2346      */
2347     @Test
testNetworkSettingsPermission()2348     public void testNetworkSettingsPermission() {
2349         final PackageManager pm = sContext.getPackageManager();
2350 
2351         final ArraySet<String> allowedPackages = new ArraySet();
2352         final ArraySet<Integer> allowedUIDs = new ArraySet();
2353         // explicitly add allowed UIDs
2354         allowedUIDs.add(Process.SYSTEM_UID);
2355         allowedUIDs.add(Process.SHELL_UID);
2356         allowedUIDs.add(Process.PHONE_UID);
2357         allowedUIDs.add(Process.NETWORK_STACK_UID);
2358         if (!SdkLevel.isAtLeastV()) {
2359             allowedUIDs.add(Process.NFC_UID);
2360         }
2361 
2362         // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using
2363         // this fact to determined allowed package name for sysui. This is a signature permission,
2364         // so allow any package with this permission.
2365         final List<PackageInfo> sysuiPackages = pm.getPackagesHoldingPermissions(new String[] {
2366                 android.Manifest.permission.BIND_QUICK_SETTINGS_TILE
2367         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2368         for (PackageInfo info : sysuiPackages) {
2369             allowedPackages.add(info.packageName);
2370         }
2371 
2372         // the captive portal flow also currently holds the NETWORK_SETTINGS permission
2373         final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
2374         final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
2375         if (ri != null) {
2376             allowedPackages.add(ri.activityInfo.packageName);
2377         }
2378 
2379         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2380                 android.Manifest.permission.NETWORK_SETTINGS
2381         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2382         StringBuilder stringBuilder = new StringBuilder();
2383         for (PackageInfo pi : holding) {
2384             String packageName = pi.packageName;
2385 
2386             // this is an explicitly allowed package
2387             if (allowedPackages.contains(packageName)) continue;
2388 
2389             // now check if the packages are from allowed UIDs
2390             int uid = -1;
2391             try {
2392                 uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM);
2393             } catch (PackageManager.NameNotFoundException e) {
2394                 continue;
2395             }
2396             if (!allowedUIDs.contains(uid)) {
2397                 stringBuilder.append("The NETWORK_SETTINGS permission must not be held by "
2398                     + packageName + ":" + uid + " and must be revoked for security reasons\n");
2399             }
2400         }
2401         if (stringBuilder.length() > 0) {
2402             fail(stringBuilder.toString());
2403         }
2404     }
2405 
2406     /**
2407      * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is
2408      * only held by the device setup wizard application.
2409      * <p>
2410      * Only the SetupWizard app should <em>ever</em> attempt to acquire this
2411      * permission, since it would give those apps extremely broad access to connectivity
2412      * functionality.  The permission is intended to be granted to only the device setup wizard.
2413      */
2414     @Test
testNetworkSetupWizardPermission()2415     public void testNetworkSetupWizardPermission() {
2416         final ArraySet<String> allowedPackages = new ArraySet();
2417 
2418         final PackageManager pm = sContext.getPackageManager();
2419 
2420         final Intent intent = new Intent(Intent.ACTION_MAIN);
2421         intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
2422         final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
2423         String validPkg = "";
2424         if (ri != null) {
2425             allowedPackages.add(ri.activityInfo.packageName);
2426             validPkg = ri.activityInfo.packageName;
2427         }
2428 
2429         final Intent preIntent = new Intent("com.android.setupwizard.OEM_PRE_SETUP");
2430         preIntent.addCategory(Intent.CATEGORY_DEFAULT);
2431         final ResolveInfo preRi = pm
2432             .resolveActivity(preIntent, PackageManager.MATCH_DISABLED_COMPONENTS);
2433         String prePackageName = "";
2434         if (null != preRi) {
2435             prePackageName = preRi.activityInfo.packageName;
2436         }
2437 
2438         final Intent postIntent = new Intent("com.android.setupwizard.OEM_POST_SETUP");
2439         postIntent.addCategory(Intent.CATEGORY_DEFAULT);
2440         final ResolveInfo postRi = pm
2441             .resolveActivity(postIntent, PackageManager.MATCH_DISABLED_COMPONENTS);
2442         String postPackageName = "";
2443         if (null != postRi) {
2444             postPackageName = postRi.activityInfo.packageName;
2445         }
2446         if (!TextUtils.isEmpty(prePackageName) && !TextUtils.isEmpty(postPackageName)
2447             && prePackageName.equals(postPackageName)) {
2448             allowedPackages.add(prePackageName);
2449         }
2450 
2451         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[]{
2452             android.Manifest.permission.NETWORK_SETUP_WIZARD
2453         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2454         for (PackageInfo pi : holding) {
2455             if (!allowedPackages.contains(pi.packageName)) {
2456                 fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName
2457                     + " and must be revoked for security reasons"
2458                     + " | validPkg=" + validPkg);
2459             }
2460         }
2461     }
2462 
2463     /**
2464      * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission
2465      * is only held by the device managed provisioning application.
2466      * <p>
2467      * Only the ManagedProvisioning app should <em>ever</em> attempt to acquire this
2468      * permission, since it would give those apps extremely broad access to connectivity
2469      * functionality.  The permission is intended to be granted to only the device managed
2470      * provisioning.
2471      */
2472     @Test
testNetworkManagedProvisioningPermission()2473     public void testNetworkManagedProvisioningPermission() {
2474         final PackageManager pm = sContext.getPackageManager();
2475 
2476         // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the
2477         // managed provisioning app.
2478         // Ensure that the package exists.
2479         final Intent intent = new Intent(Intent.ACTION_MAIN);
2480         intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME);
2481         final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
2482         String validPkg = "";
2483         if (ri != null) {
2484             validPkg = ri.activityInfo.packageName;
2485         }
2486         String dpmHolderName = null;
2487         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2488             DevicePolicyManager dpm = sContext.getSystemService(DevicePolicyManager.class);
2489             if (dpm != null) {
2490                 dpmHolderName = dpm.getDevicePolicyManagementRoleHolderPackage();
2491             }
2492         }
2493 
2494         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2495                 android.Manifest.permission.NETWORK_MANAGED_PROVISIONING
2496         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2497         for (PackageInfo pi : holding) {
2498             if (!Objects.equals(pi.packageName, validPkg)
2499                     && !Objects.equals(pi.packageName, dpmHolderName)) {
2500                 fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by "
2501                         + pi.packageName + " and must be revoked for security reasons ["
2502                         + validPkg + ", " + dpmHolderName + "]");
2503             }
2504         }
2505     }
2506 
2507     /**
2508      * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission
2509      * is held by at most one application.
2510      */
2511     @Test
testWifiSetDeviceMobilityStatePermission()2512     public void testWifiSetDeviceMobilityStatePermission() {
2513         final PackageManager pm = sContext.getPackageManager();
2514 
2515         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2516                 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE
2517         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2518 
2519         List<String> uniquePackageNames = holding
2520                 .stream()
2521                 .map(pi -> pi.packageName)
2522                 .distinct()
2523                 .collect(Collectors.toList());
2524 
2525         if (uniquePackageNames.size() > 1) {
2526             fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one "
2527                     + "application, but is held by " + uniquePackageNames.size() + " applications: "
2528                     + String.join(", ", uniquePackageNames));
2529         }
2530     }
2531 
2532     /**
2533      * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission
2534      * is held by at most one application.
2535      */
2536     @Test
testNetworkCarrierProvisioningPermission()2537     public void testNetworkCarrierProvisioningPermission() {
2538         final PackageManager pm = sContext.getPackageManager();
2539 
2540         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2541                 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
2542         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2543 
2544         List<String> uniquePackageNames = holding
2545                 .stream()
2546                 .map(pi -> pi.packageName)
2547                 .distinct()
2548                 .collect(Collectors.toList());
2549 
2550         if (uniquePackageNames.size() > 2) {
2551             fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two "
2552                     + "applications, but is held by " + uniquePackageNames.size() + " applications: "
2553                     + String.join(", ", uniquePackageNames));
2554         }
2555     }
2556 
2557     /**
2558      * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE}
2559      * permission is held by at most two applications.
2560      */
2561     @Test
testUpdateWifiUsabilityStatsScorePermission()2562     public void testUpdateWifiUsabilityStatsScorePermission() {
2563         final PackageManager pm = sContext.getPackageManager();
2564 
2565         final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
2566                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE
2567         }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
2568 
2569         Set<String> uniqueNonSystemPackageNames = new HashSet<>();
2570         for (PackageInfo pi : holding) {
2571             String packageName = pi.packageName;
2572             // Shell is allowed to hold this permission for testing.
2573             int uid = -1;
2574             try {
2575                 uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM);
2576             } catch (PackageManager.NameNotFoundException e) {
2577                 continue;
2578             }
2579             if (uid == Process.SHELL_UID) continue;
2580 
2581             uniqueNonSystemPackageNames.add(packageName);
2582         }
2583 
2584         if (uniqueNonSystemPackageNames.size() > 2) {
2585             fail("The WIFI_UPDATE_USABILITY_STATS_SCORE permission must not be held by more than "
2586                     + "two applications, but is held by " + uniqueNonSystemPackageNames.size()
2587                     + " applications: " + String.join(", ", uniqueNonSystemPackageNames));
2588         }
2589     }
2590 
turnScreenOnNoDelay()2591     private static void turnScreenOnNoDelay() throws Exception {
2592         if (sWakeLock.isHeld()) sWakeLock.release();
2593         sUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
2594         sUiDevice.executeShellCommand("wm dismiss-keyguard");
2595     }
2596 
turnScreenOn()2597     private void turnScreenOn() throws Exception {
2598         turnScreenOnNoDelay();
2599         // Since the screen on/off intent is ordered, they will not be sent right now.
2600         Thread.sleep(DURATION_SCREEN_TOGGLE);
2601     }
2602 
turnScreenOffNoDelay()2603     private void turnScreenOffNoDelay() throws Exception {
2604         sUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP");
2605     }
2606 
turnScreenOff()2607     private void turnScreenOff() throws Exception {
2608         if (!sWakeLock.isHeld()) sWakeLock.acquire();
2609         turnScreenOffNoDelay();
2610         // Since the screen on/off intent is ordered, they will not be sent right now.
2611         Thread.sleep(DURATION_SCREEN_TOGGLE);
2612     }
2613 
assertWifiScanningIsOn()2614     private void assertWifiScanningIsOn() {
2615         if (!sWifiManager.isScanAlwaysAvailable()) {
2616             fail("Wi-Fi scanning should be on.");
2617         }
2618     }
2619 
runWithScanning(ThrowingRunnable r, boolean isEnabled)2620     private void runWithScanning(ThrowingRunnable r, boolean isEnabled) throws Exception {
2621         boolean scanModeChangedForTest = false;
2622         if (sWifiManager.isScanAlwaysAvailable() != isEnabled) {
2623             ShellIdentityUtils.invokeWithShellPermissions(
2624                     () -> sWifiManager.setScanAlwaysAvailable(isEnabled));
2625             scanModeChangedForTest = true;
2626         }
2627         try {
2628             r.run();
2629         } finally {
2630             if (scanModeChangedForTest) {
2631                 ShellIdentityUtils.invokeWithShellPermissions(
2632                         () -> sWifiManager.setScanAlwaysAvailable(!isEnabled));
2633             }
2634         }
2635     }
2636 
2637     /**
2638      * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled
2639      * but location is on.
2640      * @throws Exception
2641      */
2642     @Test
testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled()2643     public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception {
2644         if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) {
2645             // TV and auto do not support the setting options of WIFI scanning and Bluetooth
2646             // scanning
2647             return;
2648         }
2649 
2650         if (!hasLocationFeature()) {
2651             // skip the test if location is not supported
2652             return;
2653         }
2654         if (!isLocationEnabled()) {
2655             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
2656                     + " empty when location is disabled!");
2657         }
2658         runWithScanning(() -> {
2659             setWifiEnabled(false);
2660             turnScreenOn();
2661             assertWifiScanningIsOn();
2662             // Toggle screen and verify Wi-Fi scanning is still on.
2663             turnScreenOff();
2664             assertWifiScanningIsOn();
2665             turnScreenOn();
2666             assertWifiScanningIsOn();
2667         }, true /* run with enabled*/);
2668     }
2669 
2670     /**
2671      * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled.
2672      * @throws Exception
2673      */
2674     @Test
testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled()2675     public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception {
2676         if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) {
2677             // TV and auto do not support the setting options of WIFI scanning and Bluetooth
2678             // scanning
2679             return;
2680         }
2681 
2682         if (!hasLocationFeature()) {
2683             // skip the test if location is not supported
2684             return;
2685         }
2686         if (!isLocationEnabled()) {
2687             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
2688                     + " empty when location is disabled!");
2689         }
2690         runWithScanning(() -> {
2691             setWifiEnabled(true);
2692             turnScreenOn();
2693             assertWifiScanningIsOn();
2694             // Toggle screen and verify Wi-Fi scanning is still on.
2695             turnScreenOff();
2696             assertWifiScanningIsOn();
2697             turnScreenOn();
2698             assertWifiScanningIsOn();
2699         }, true /* run with enabled*/);
2700     }
2701 
2702     /**
2703      * Verify that the platform supports a reasonable number of suggestions per app.
2704      * @throws Exception
2705      */
2706     @Test
testMaxNumberOfNetworkSuggestionsPerApp()2707     public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception {
2708         assertTrue(sWifiManager.getMaxNumberOfNetworkSuggestionsPerApp()
2709                 > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP);
2710     }
2711 
verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)2712     private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)
2713             throws Exception {
2714         // Register callback to get SoftApCapability
2715         sWifiManager.registerSoftApCallback(executor, callback);
2716         PollingCheck.check(
2717                 "SoftAp register failed!", 5_000,
2718                 () -> {
2719                     executor.runAll();
2720                     // Verify callback is run on the supplied executor and called
2721                     return callback.getOnStateChangedCalled()
2722                             && callback.getOnSoftapInfoChangedCalledCount() > 0
2723                             && callback.getOnSoftApCapabilityChangedCalled()
2724                             && callback.getOnConnectedClientCalled();
2725                 });
2726     }
2727 
verifyLohsRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)2728     private void verifyLohsRegisterSoftApCallback(TestExecutor executor,
2729             TestSoftApCallback callback) throws Exception {
2730         // Register callback to get SoftApCapability
2731         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2732             sWifiManager.registerLocalOnlyHotspotSoftApCallback(executor, callback);
2733         } else {
2734             sWifiManager.registerSoftApCallback(executor, callback);
2735         }
2736         PollingCheck.check(
2737                 "SoftAp register failed!", 5_000,
2738                 () -> {
2739                     executor.runAll();
2740                     // Verify callback is run on the supplied executor and called
2741                     return callback.getOnStateChangedCalled() &&
2742                             callback.getOnSoftapInfoChangedCalledCount() > 0 &&
2743                             callback.getOnSoftApCapabilityChangedCalled() &&
2744                             callback.getOnConnectedClientCalled();
2745                 });
2746     }
2747 
verifySetGetSoftApConfig(SoftApConfiguration targetConfig)2748     private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) {
2749         assertTrue(sWifiManager.validateSoftApConfiguration(targetConfig));
2750         sWifiManager.setSoftApConfiguration(targetConfig);
2751         // Bssid set dodesn't support for tethered hotspot
2752         SoftApConfiguration currentConfig = sWifiManager.getSoftApConfiguration();
2753         compareSoftApConfiguration(targetConfig, currentConfig);
2754         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
2755             assertTrue(currentConfig.isUserConfiguration());
2756         }
2757         assertNotNull(currentConfig.getPersistentRandomizedMacAddress());
2758 
2759         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2760             // Verify set/get with the deprecated set/getSsid()
2761             SoftApConfiguration oldSsidConfig = new SoftApConfiguration.Builder(targetConfig)
2762                     .setWifiSsid(null)
2763                     .setSsid(targetConfig.getSsid()).build();
2764             sWifiManager.setSoftApConfiguration(oldSsidConfig);
2765             currentConfig = sWifiManager.getSoftApConfiguration();
2766             compareSoftApConfiguration(oldSsidConfig, currentConfig);
2767         }
2768     }
2769 
compareSoftApConfiguration(SoftApConfiguration currentConfig, SoftApConfiguration testSoftApConfig)2770     private void compareSoftApConfiguration(SoftApConfiguration currentConfig,
2771         SoftApConfiguration testSoftApConfig) {
2772         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2773             assertEquals(currentConfig.getWifiSsid(), testSoftApConfig.getWifiSsid());
2774         }
2775         assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid());
2776         assertEquals(currentConfig.getBssid(), testSoftApConfig.getBssid());
2777         assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType());
2778         assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase());
2779         assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid());
2780         assertEquals(currentConfig.getBand(), testSoftApConfig.getBand());
2781         assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel());
2782         assertEquals(currentConfig.getMaxNumberOfClients(),
2783                 testSoftApConfig.getMaxNumberOfClients());
2784         assertEquals(currentConfig.isAutoShutdownEnabled(),
2785                 testSoftApConfig.isAutoShutdownEnabled());
2786         assertEquals(currentConfig.getShutdownTimeoutMillis(),
2787                 testSoftApConfig.getShutdownTimeoutMillis());
2788         assertEquals(currentConfig.isClientControlByUserEnabled(),
2789                 testSoftApConfig.isClientControlByUserEnabled());
2790         assertEquals(currentConfig.getAllowedClientList(),
2791                 testSoftApConfig.getAllowedClientList());
2792         assertEquals(currentConfig.getBlockedClientList(),
2793                 testSoftApConfig.getBlockedClientList());
2794         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
2795             assertEquals(currentConfig.getMacRandomizationSetting(),
2796                     testSoftApConfig.getMacRandomizationSetting());
2797             assertEquals(currentConfig.getChannels().toString(),
2798                     testSoftApConfig.getChannels().toString());
2799             assertEquals(currentConfig.isBridgedModeOpportunisticShutdownEnabled(),
2800                     testSoftApConfig.isBridgedModeOpportunisticShutdownEnabled());
2801             assertEquals(currentConfig.isIeee80211axEnabled(),
2802                     testSoftApConfig.isIeee80211axEnabled());
2803             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
2804                 assertEquals(currentConfig.getBridgedModeOpportunisticShutdownTimeoutMillis(),
2805                         testSoftApConfig.getBridgedModeOpportunisticShutdownTimeoutMillis());
2806                 assertEquals(currentConfig.isIeee80211beEnabled(),
2807                         testSoftApConfig.isIeee80211beEnabled());
2808                 assertEquals(currentConfig.getVendorElements(),
2809                         testSoftApConfig.getVendorElements());
2810                 assertArrayEquals(
2811                         currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ),
2812                         testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ));
2813                 assertArrayEquals(
2814                         currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ),
2815                         testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ));
2816                 assertArrayEquals(
2817                         currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ),
2818                         testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ));
2819                 assertEquals(currentConfig.getMaxChannelBandwidth(),
2820                         testSoftApConfig.getMaxChannelBandwidth());
2821             }
2822             if (Flags.androidVWifiApi()
2823                     && SdkLevel.isAtLeastV()) {
2824                 assertTrue(Objects.equals(
2825                         currentConfig.getVendorData(), testSoftApConfig.getVendorData()));
2826             }
2827         }
2828     }
2829 
turnOffWifiAndTetheredHotspotIfEnabled()2830     private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception {
2831         if (sWifiManager.isWifiEnabled()) {
2832             Log.d(TAG, "Turn off WiFi");
2833             sWifiManager.setWifiEnabled(false);
2834             PollingCheck.check("Wifi turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
2835                     () -> !sWifiManager.isWifiEnabled());
2836         }
2837         if (sWifiManager.isWifiApEnabled()) {
2838             sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
2839             Log.d(TAG, "Turn off tethered Hotspot");
2840             PollingCheck.check("SoftAp turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
2841                     () -> !sWifiManager.isWifiApEnabled());
2842         }
2843     }
2844 
verifyBridgedModeSoftApCallback(TestExecutor executor, TestSoftApCallback callback, boolean shouldFallbackSingleApMode, boolean isEnabled)2845     private void verifyBridgedModeSoftApCallback(TestExecutor executor,
2846             TestSoftApCallback callback, boolean shouldFallbackSingleApMode, boolean isEnabled)
2847             throws Exception {
2848             // Verify state and info callback value as expected
2849             PollingCheck.check(
2850                     "SoftAp state and info on bridged AP mode are mismatch!!!"
2851                     + " shouldFallbackSingleApMode = " + shouldFallbackSingleApMode
2852                     + ", isEnabled = "  + isEnabled, 10_000,
2853                     () -> {
2854                         executor.runAll();
2855                         int expectedState = isEnabled ? WifiManager.WIFI_AP_STATE_ENABLED
2856                                 : WifiManager.WIFI_AP_STATE_DISABLED;
2857                         int expectedInfoSize = isEnabled
2858                                 ? (shouldFallbackSingleApMode ? 1 : 2) : 0;
2859                         return expectedState == callback.getCurrentState()
2860                                 && callback.getCurrentSoftApInfoList().size() == expectedInfoSize;
2861                     });
2862     }
2863 
shouldFallbackToSingleAp(int[] bands, SoftApCapability capability)2864     private boolean shouldFallbackToSingleAp(int[] bands, SoftApCapability capability) {
2865         for (int band : bands) {
2866             if (capability.getSupportedChannelList(band).length == 0) {
2867                 return true;
2868             }
2869         }
2870         return false;
2871     }
2872 
getAvailableBandAndChannelForTesting(SoftApCapability capability)2873     private SparseIntArray getAvailableBandAndChannelForTesting(SoftApCapability capability) {
2874         final int[] bands = {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ,
2875               SoftApConfiguration.BAND_6GHZ, SoftApConfiguration.BAND_60GHZ};
2876         SparseIntArray testBandsAndChannels = new SparseIntArray();
2877         if (!ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
2878             testBandsAndChannels.put(SoftApConfiguration.BAND_2GHZ, 1);
2879             return testBandsAndChannels;
2880         }
2881         for (int band : bands) {
2882             int[] supportedList = capability.getSupportedChannelList(band);
2883             if (supportedList.length != 0) {
2884                 testBandsAndChannels.put(band, supportedList[0]);
2885             }
2886         }
2887         return testBandsAndChannels;
2888     }
2889 
2890     @Test
testLastConfiguredPassphraseIsKeepInSoftApConfigurationWhenChangingToNone()2891     public void testLastConfiguredPassphraseIsKeepInSoftApConfigurationWhenChangingToNone()
2892             throws Exception {
2893         final SoftApConfiguration currentConfig = ShellIdentityUtils.invokeWithShellPermissions(
2894                 sWifiManager::getSoftApConfiguration);
2895         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
2896         try {
2897             uiAutomation.adoptShellPermissionIdentity();
2898             Mutable<String> lastPassphrase = new Mutable<>();
2899             final String testPassphrase = "testPassphrase";
2900             sWifiManager.setSoftApConfiguration(
2901                     new SoftApConfiguration.Builder(currentConfig)
2902                             .setPassphrase(testPassphrase,
2903                                     SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build());
2904             sWifiManager.queryLastConfiguredTetheredApPassphraseSinceBoot(mExecutor,
2905                     new Consumer<String>() {
2906                     @Override
2907                     public void accept(String value) {
2908                         synchronized (mLock) {
2909                             lastPassphrase.value = value;
2910                             mLock.notify();
2911                         }
2912                     }
2913                 });
2914             synchronized (mLock) {
2915                 mLock.wait(TEST_WAIT_DURATION_MS);
2916             }
2917             assertEquals(lastPassphrase.value, testPassphrase);
2918 
2919             sWifiManager.setSoftApConfiguration(
2920                     new SoftApConfiguration.Builder(currentConfig)
2921                             .setPassphrase(null,
2922                                     SoftApConfiguration.SECURITY_TYPE_OPEN).build());
2923             sWifiManager.queryLastConfiguredTetheredApPassphraseSinceBoot(mExecutor,
2924                     new Consumer<String>() {
2925                     @Override
2926                     public void accept(String value) {
2927                         synchronized (mLock) {
2928                             lastPassphrase.value = value;
2929                             mLock.notify();
2930                         }
2931                     }
2932                 });
2933             synchronized (mLock) {
2934                 mLock.wait(TEST_WAIT_DURATION_MS);
2935             }
2936             assertEquals(lastPassphrase.value, testPassphrase);
2937         } finally {
2938             // Restore SoftApConfiguration
2939             sWifiManager.setSoftApConfiguration(currentConfig);
2940             uiAutomation.dropShellPermissionIdentity();
2941         }
2942     }
2943 
2944     /**
2945      * Skip the test if telephony is not supported and default country code
2946      * is not stored in system property.
2947      */
shouldSkipCountryCodeDependentTest()2948     private boolean shouldSkipCountryCodeDependentTest() {
2949         String countryCode = SystemProperties.get(BOOT_DEFAULT_WIFI_COUNTRY_CODE);
2950         return TextUtils.isEmpty(countryCode) && !WifiFeature.isTelephonySupported(sContext);
2951     }
2952 
2953     /**
2954      * Test SoftApConfiguration#getPersistentRandomizedMacAddress(). There are two test cases in
2955      * this test.
2956      * 1. configure two different SoftApConfigurations (different SSID) and verify that randomized
2957      * MAC address is different.
2958      * 2. configure A then B then A (SSIDs) and verify that the 1st and 3rd MAC addresses are the
2959      * same.
2960      */
2961     @Test
testSoftApConfigurationGetPersistentRandomizedMacAddress()2962     public void testSoftApConfigurationGetPersistentRandomizedMacAddress() throws Exception {
2963         SoftApConfiguration currentConfig = ShellIdentityUtils.invokeWithShellPermissions(
2964                 sWifiManager::getSoftApConfiguration);
2965         final String ssid = currentConfig.getSsid().length() <= 28
2966                 ? currentConfig.getSsid() + "test"
2967                 : "AndroidTest";
2968         ShellIdentityUtils.invokeWithShellPermissions(
2969                 () -> sWifiManager.setSoftApConfiguration(new SoftApConfiguration.Builder()
2970                 .setSsid(ssid).build()));
2971         SoftApConfiguration changedSsidConfig = ShellIdentityUtils.invokeWithShellPermissions(
2972                 sWifiManager::getSoftApConfiguration);
2973         assertNotEquals(currentConfig.getPersistentRandomizedMacAddress(),
2974                 changedSsidConfig.getPersistentRandomizedMacAddress());
2975 
2976         // set currentConfig
2977         ShellIdentityUtils.invokeWithShellPermissions(
2978                 () -> sWifiManager.setSoftApConfiguration(currentConfig));
2979 
2980         SoftApConfiguration changedSsidBackConfig = ShellIdentityUtils.invokeWithShellPermissions(
2981                 sWifiManager::getSoftApConfiguration);
2982 
2983         assertEquals(currentConfig.getPersistentRandomizedMacAddress(),
2984                 changedSsidBackConfig.getPersistentRandomizedMacAddress());
2985     }
2986 
2987     /**
2988      * Test bridged AP enable succeeful when device supports it.
2989      * Also verify the callback info update correctly.
2990      * @throws Exception
2991      */
2992     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
2993     @Test
testTetheredBridgedAp()2994     public void testTetheredBridgedAp() throws Exception {
2995         // check that softap bridged mode is supported by the device
2996         if (!sWifiManager.isBridgedApConcurrencySupported()) {
2997             return;
2998         }
2999         runWithScanning(() -> {
3000             UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
3001                     .getUiAutomation();
3002             TestExecutor executor = new TestExecutor();
3003             TestSoftApCallback callback = new TestSoftApCallback(mLock);
3004             try {
3005                 uiAutomation.adoptShellPermissionIdentity();
3006                 // Off/On Wifi to make sure that we get the supported channel
3007                 turnOffWifiAndTetheredHotspotIfEnabled();
3008                 sWifiManager.setWifiEnabled(true);
3009                 PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
3010                         () -> sWifiManager.isWifiEnabled());
3011                 turnOffWifiAndTetheredHotspotIfEnabled();
3012                 verifyRegisterSoftApCallback(executor, callback);
3013                 if (!callback.getCurrentSoftApCapability()
3014                         .areFeaturesSupported(SOFTAP_FEATURE_ACS_OFFLOAD)) {
3015                     return;
3016                 }
3017                 int[] testBands = {SoftApConfiguration.BAND_2GHZ,
3018                         SoftApConfiguration.BAND_5GHZ};
3019                 int[] expectedBands = {SoftApConfiguration.BAND_2GHZ,
3020                         SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ};
3021                 // Test bridged SoftApConfiguration set and get (setBands)
3022                 SoftApConfiguration testSoftApConfig =
3023                         generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
3024                         .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
3025                         .setBands(expectedBands)
3026                         .build();
3027 
3028                 boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp(testBands,
3029                         callback.getCurrentSoftApCapability());
3030                 verifySetGetSoftApConfig(testSoftApConfig);
3031 
3032                 // start tethering which used to verify startTetheredHotspot
3033                 sTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
3034                     new TetheringManager.StartTetheringCallback() {
3035                         @Override
3036                         public void onTetheringFailed(final int result) {
3037                         }
3038                     });
3039                 verifyBridgedModeSoftApCallback(executor, callback,
3040                         shouldFallbackToSingleAp, true /* enabled */);
3041                 // stop tethering which used to verify stopSoftAp
3042                 sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
3043                 verifyBridgedModeSoftApCallback(executor, callback,
3044                         shouldFallbackToSingleAp, false /* disabled */);
3045             } finally {
3046                 sWifiManager.unregisterSoftApCallback(callback);
3047                 uiAutomation.dropShellPermissionIdentity();
3048             }
3049         }, false /* run with disabled */);
3050     }
3051 
3052     /**
3053      * Test bridged AP with forced channel config enable succeeful when device supports it.
3054      * Also verify the callback info update correctly.
3055      * @throws Exception
3056      */
3057     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
3058     @Test
testTetheredBridgedApWifiForcedChannel()3059     public void testTetheredBridgedApWifiForcedChannel() throws Exception {
3060         // check that softap bridged mode is supported by the device
3061         if (!sWifiManager.isBridgedApConcurrencySupported()) {
3062             return;
3063         }
3064         runWithScanning(() -> {
3065             UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
3066                     .getUiAutomation();
3067             TestExecutor executor = new TestExecutor();
3068             TestSoftApCallback callback = new TestSoftApCallback(mLock);
3069             try {
3070                 uiAutomation.adoptShellPermissionIdentity();
3071                 // Off/On Wifi to make sure that we get the supported channel
3072                 turnOffWifiAndTetheredHotspotIfEnabled();
3073                 sWifiManager.setWifiEnabled(true);
3074                 PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
3075                         () -> sWifiManager.isWifiEnabled());
3076                 turnOffWifiAndTetheredHotspotIfEnabled();
3077                 verifyRegisterSoftApCallback(executor, callback);
3078 
3079                 boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp(
3080                         new int[] {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ},
3081                         callback.getCurrentSoftApCapability());
3082 
3083                 // Test when there are supported channels in both of the bands.
3084                 if (!shouldFallbackToSingleAp) {
3085                     // Test bridged SoftApConfiguration set and get (setChannels)
3086                     SparseIntArray dual_channels = new SparseIntArray(2);
3087                     dual_channels.put(SoftApConfiguration.BAND_2GHZ,
3088                             callback.getCurrentSoftApCapability()
3089                             .getSupportedChannelList(SoftApConfiguration.BAND_2GHZ)[0]);
3090                     dual_channels.put(SoftApConfiguration.BAND_5GHZ,
3091                             callback.getCurrentSoftApCapability()
3092                             .getSupportedChannelList(SoftApConfiguration.BAND_5GHZ)[0]);
3093                     SoftApConfiguration testSoftApConfig =
3094                             generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
3095                             .setPassphrase(TEST_PASSPHRASE,
3096                                     SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
3097                             .setChannels(dual_channels)
3098                             .build();
3099 
3100                     verifySetGetSoftApConfig(testSoftApConfig);
3101 
3102                     // start tethering which used to verify startTetheredHotspot
3103                     sTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
3104                         new TetheringManager.StartTetheringCallback() {
3105                             @Override
3106                             public void onTetheringFailed(final int result) {
3107                             }
3108                         });
3109                     verifyBridgedModeSoftApCallback(executor, callback,
3110                             shouldFallbackToSingleAp, true /* enabled */);
3111                     // stop tethering which used to verify stopSoftAp
3112                     sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
3113                     verifyBridgedModeSoftApCallback(executor, callback,
3114                             shouldFallbackToSingleAp, false /* disabled */);
3115                 }
3116             } finally {
3117                 sWifiManager.unregisterSoftApCallback(callback);
3118                 uiAutomation.dropShellPermissionIdentity();
3119             }
3120         }, false /* run with disabled */);
3121     }
3122 
3123     /**
3124      * Test startTetheringRequest() starts a soft AP and relays the TetheringRequest object back via
3125      * SoftApCallback.
3126      * @throws Exception
3127      */
3128     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
3129     @Test
testStartTetheredHotspotWithTetheringRequest()3130     public void testStartTetheredHotspotWithTetheringRequest() throws Exception {
3131         // check that softap  is supported by the device
3132         if (!sWifiManager.isPortableHotspotSupported()) {
3133             return;
3134         }
3135         runWithScanning(() -> {
3136             TestExecutor executor = new TestExecutor();
3137             TestSoftApCallback callback = new TestSoftApCallback(mLock);
3138             try {
3139                 TetheringManager.TetheringRequest request =
3140                         new TetheringManager.TetheringRequest.Builder(
3141                                 TetheringManager.TETHERING_WIFI).build();
3142                 sWifiManager.startTetheredHotspot(request, executor, callback);
3143                 fail("startTetheredHotspot succeeded even without NETWORK_STACK permission!");
3144             } catch (SecurityException e) {
3145                 // Expected to fail without NETWORK_STACK
3146             }
3147         }, false /* run with disabled */);
3148     }
3149 
3150     /**
3151      * Verify that the configuration from getSoftApConfiguration is same as the configuration which
3152      * set by setSoftApConfiguration. And depends softap capability callback to test different
3153      * configuration.
3154      * @throws Exception
3155      */
3156     @RequiresDevice
3157     @Test
testSetGetSoftApConfigurationAndSoftApCapabilityCallback()3158     public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception {
3159         // check that softap mode is supported by the device
3160         if (!sWifiManager.isPortableHotspotSupported()) {
3161             return;
3162         }
3163         if (shouldSkipCountryCodeDependentTest()) {
3164             // skip the test  when there is no Country Code available
3165             return;
3166         }
3167         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3168         TestExecutor executor = new TestExecutor();
3169         TestSoftApCallback callback = new TestSoftApCallback(mLock);
3170         try {
3171             uiAutomation.adoptShellPermissionIdentity();
3172             turnOffWifiAndTetheredHotspotIfEnabled();
3173             verifyRegisterSoftApCallback(executor, callback);
3174 
3175             SoftApConfiguration.Builder softApConfigBuilder =
3176                      generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
3177                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
3178                     .setAutoShutdownEnabled(true)
3179                     .setShutdownTimeoutMillis(100000)
3180                     .setBand(getAvailableBandAndChannelForTesting(
3181                             callback.getCurrentSoftApCapability()).keyAt(0))
3182                     .setHiddenSsid(false);
3183 
3184             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
3185                 softApConfigBuilder.setBridgedModeOpportunisticShutdownTimeoutMillis(30_000);
3186                 softApConfigBuilder.setVendorElements(TEST_VENDOR_ELEMENTS);
3187                 softApConfigBuilder.setAllowedAcsChannels(
3188                         SoftApConfiguration.BAND_2GHZ, new int[] {1, 6, 11});
3189                 softApConfigBuilder.setAllowedAcsChannels(
3190                         SoftApConfiguration.BAND_5GHZ, new int[] {149});
3191                 softApConfigBuilder.setAllowedAcsChannels(
3192                         SoftApConfiguration.BAND_6GHZ, new int[] {});
3193                 softApConfigBuilder.setMaxChannelBandwidth(SoftApInfo.CHANNEL_WIDTH_80MHZ);
3194             }
3195 
3196             if (Flags.androidVWifiApi()
3197                     && SdkLevel.isAtLeastV()) {
3198                 OuiKeyedData vendorDataElement =
3199                         new OuiKeyedData.Builder(0x00112233, new PersistableBundle()).build();
3200                 softApConfigBuilder.setVendorData(Arrays.asList(vendorDataElement));
3201             }
3202 
3203             // Test SoftApConfiguration set and get
3204             verifySetGetSoftApConfig(softApConfigBuilder.build());
3205 
3206             boolean isSupportCustomizedMac = callback.getCurrentSoftApCapability()
3207                         .areFeaturesSupported(
3208                         SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION)
3209                     && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S);
3210 
3211             //Test MAC_ADDRESS_CUSTOMIZATION supported config
3212             if (isSupportCustomizedMac) {
3213                 softApConfigBuilder.setBssid(TEST_MAC)
3214                         .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE);
3215 
3216                 // Test SoftApConfiguration set and get
3217                 verifySetGetSoftApConfig(softApConfigBuilder.build());
3218             }
3219 
3220             assertThat(callback.getCurrentSoftApCapability().getMaxSupportedClients())
3221                     .isGreaterThan(0);
3222             // Test CLIENT_FORCE_DISCONNECT supported config.
3223             if (callback.getCurrentSoftApCapability()
3224                     .areFeaturesSupported(
3225                     SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) {
3226                 softApConfigBuilder.setMaxNumberOfClients(10);
3227                 softApConfigBuilder.setClientControlByUserEnabled(true);
3228                 softApConfigBuilder.setBlockedClientList(new ArrayList<>());
3229                 softApConfigBuilder.setAllowedClientList(new ArrayList<>());
3230                 verifySetGetSoftApConfig(softApConfigBuilder.build());
3231             }
3232 
3233             // Test SAE config
3234             if (callback.getCurrentSoftApCapability()
3235                     .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) {
3236                 softApConfigBuilder
3237                         .setPassphrase(TEST_PASSPHRASE,
3238                           SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
3239                 verifySetGetSoftApConfig(softApConfigBuilder.build());
3240                 softApConfigBuilder
3241                         .setPassphrase(TEST_PASSPHRASE,
3242                         SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
3243                 verifySetGetSoftApConfig(softApConfigBuilder.build());
3244             }
3245 
3246             // Test 11 BE control config
3247             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
3248                 if (callback.getCurrentSoftApCapability()
3249                         .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE)) {
3250                     softApConfigBuilder.setIeee80211beEnabled(true);
3251                     verifySetGetSoftApConfig(softApConfigBuilder.build());
3252                 }
3253             }
3254 
3255             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
3256                 // Test 11 AX control config.
3257                 if (callback.getCurrentSoftApCapability()
3258                         .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX)) {
3259                     softApConfigBuilder.setIeee80211axEnabled(true);
3260                     verifySetGetSoftApConfig(softApConfigBuilder.build());
3261                 }
3262                 softApConfigBuilder.setBridgedModeOpportunisticShutdownEnabled(false);
3263                 verifySetGetSoftApConfig(softApConfigBuilder.build());
3264             }
3265 
3266         } finally {
3267             sWifiManager.unregisterSoftApCallback(callback);
3268             uiAutomation.dropShellPermissionIdentity();
3269         }
3270     }
3271 
3272     /**
3273      * Verify that startTetheredHotspot with specific channel config.
3274      * @throws Exception
3275      */
3276     @RequiresDevice
3277     @Test
testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()3278     public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()
3279             throws Exception {
3280         // check that softap mode is supported by the device
3281         if (!sWifiManager.isPortableHotspotSupported()) {
3282             return;
3283         }
3284         if (shouldSkipCountryCodeDependentTest()) {
3285             // skip the test  when there is no Country Code available
3286             return;
3287         }
3288         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3289         TestExecutor executor = new TestExecutor();
3290         TestSoftApCallback callback = new TestSoftApCallback(mLock);
3291         try {
3292             uiAutomation.adoptShellPermissionIdentity();
3293             // check that tethering is supported by the device
3294             if (!sTetheringManager.isTetheringSupported()) {
3295                 return;
3296             }
3297             turnOffWifiAndTetheredHotspotIfEnabled();
3298             verifyRegisterSoftApCallback(executor, callback);
3299 
3300             SparseIntArray testBandsAndChannels = getAvailableBandAndChannelForTesting(
3301                     callback.getCurrentSoftApCapability());
3302 
3303             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
3304                 assertNotEquals(0, testBandsAndChannels.size());
3305             }
3306             boolean isSupportCustomizedMac = callback.getCurrentSoftApCapability()
3307                     .areFeaturesSupported(
3308                     SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION)
3309                     && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S);
3310 
3311             SoftApConfiguration.Builder testSoftApConfigBuilder =
3312                      generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED)
3313                     .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
3314                     .setChannel(testBandsAndChannels.valueAt(0), testBandsAndChannels.keyAt(0));
3315 
3316             if (isSupportCustomizedMac) {
3317                 testSoftApConfigBuilder.setBssid(TEST_MAC)
3318                         .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE);
3319             }
3320 
3321             SoftApConfiguration testSoftApConfig = testSoftApConfigBuilder.build();
3322 
3323             sWifiManager.setSoftApConfiguration(testSoftApConfig);
3324 
3325             // start tethering which used to verify startTetheredHotspot
3326             sTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
3327                 new TetheringManager.StartTetheringCallback() {
3328                     @Override
3329                     public void onTetheringFailed(final int result) {
3330                     }
3331                 });
3332 
3333             // Verify state and info callback value as expected
3334             PollingCheck.check(
3335                     "SoftAp channel and state mismatch!!!", 10_000,
3336                     () -> {
3337                         executor.runAll();
3338                         int sapChannel = ScanResult.convertFrequencyMhzToChannelIfSupported(
3339                                 callback.getCurrentSoftApInfo().getFrequency());
3340                         boolean isInfoCallbackSupported =
3341                                 callback.getOnSoftapInfoChangedCalledCount() > 1;
3342                         if (isInfoCallbackSupported) {
3343                             return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState()
3344                                 && testBandsAndChannels.valueAt(0) == sapChannel;
3345                         }
3346                         return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState();
3347                     });
3348             // After Soft Ap enabled, check SoftAp info if it supported
3349             if (isSupportCustomizedMac && callback.getOnSoftapInfoChangedCalledCount() > 1) {
3350                 assertEquals(callback.getCurrentSoftApInfo().getBssid(), TEST_MAC);
3351             }
3352             if (PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S)
3353                     && callback.getOnSoftapInfoChangedCalledCount() > 1) {
3354                 assertNotEquals(callback.getCurrentSoftApInfo().getWifiStandard(),
3355                         ScanResult.WIFI_STANDARD_UNKNOWN);
3356             }
3357             if (Flags.androidVWifiApi()
3358                     && SdkLevel.isAtLeastV()
3359                     && callback.getOnSoftapInfoChangedCalledCount() > 1) {
3360                 assertNotNull(callback.getCurrentSoftApInfo().getVendorData());
3361             }
3362 
3363             if (callback.getOnSoftapInfoChangedCalledCount() > 1) {
3364                 assertTrue(callback.getCurrentSoftApInfo().getAutoShutdownTimeoutMillis() > 0);
3365             }
3366         } finally {
3367             // stop tethering which used to verify stopSoftAp
3368             sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
3369 
3370             // Verify clean up
3371             PollingCheck.check(
3372                     "Stop Softap failed", 3_000,
3373                     () -> {
3374                         executor.runAll();
3375                         return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() &&
3376                                 0 == callback.getCurrentSoftApInfo().getBandwidth() &&
3377                                 0 == callback.getCurrentSoftApInfo().getFrequency();
3378                     });
3379             if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
3380                 assertEquals(callback.getCurrentSoftApInfo().getBssid(), null);
3381                 assertEquals(ScanResult.WIFI_STANDARD_UNKNOWN,
3382                         callback.getCurrentSoftApInfo().getWifiStandard());
3383             }
3384             sWifiManager.unregisterSoftApCallback(callback);
3385             uiAutomation.dropShellPermissionIdentity();
3386         }
3387     }
3388 
3389     private static class TestActionListener implements WifiManager.ActionListener {
3390         private final Object mLock;
3391         public boolean onSuccessCalled = false;
3392         public boolean onFailedCalled = false;
3393         public int failureReason = -1;
3394 
TestActionListener(Object lock)3395         TestActionListener(Object lock) {
3396             mLock = lock;
3397         }
3398 
3399         @Override
onSuccess()3400         public void onSuccess() {
3401             synchronized (mLock) {
3402                 onSuccessCalled = true;
3403                 mLock.notify();
3404             }
3405         }
3406 
3407         @Override
onFailure(int reason)3408         public void onFailure(int reason) {
3409             synchronized (mLock) {
3410                 onFailedCalled = true;
3411                 failureReason = reason;
3412                 mLock.notify();
3413             }
3414         }
3415     }
3416 
3417     /**
3418      * Triggers connection to one of the saved networks using {@link WifiManager#connect(
3419      * int, WifiManager.ActionListener)} or {@link WifiManager#connect(WifiConfiguration,
3420      * WifiManager.ActionListener)}
3421      *
3422      * @param withNetworkId Use networkId for triggering connection, false for using
3423      *                      WifiConfiguration.
3424      * @throws Exception
3425      */
testConnect(boolean withNetworkId)3426     private void testConnect(boolean withNetworkId) throws Exception {
3427         TestActionListener actionListener = new TestActionListener(mLock);
3428         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3429         List<WifiConfiguration> savedNetworks = null;
3430         try {
3431             uiAutomation.adoptShellPermissionIdentity();
3432             // These below API's only work with privileged permissions (obtained via shell identity
3433             // for test)
3434             savedNetworks = sWifiManager.getConfiguredNetworks();
3435 
3436             // Disable all the saved networks to trigger disconnect & disable autojoin.
3437             for (WifiConfiguration network : savedNetworks) {
3438                 assertTrue(sWifiManager.disableNetwork(network.networkId));
3439             }
3440             waitForDisconnection();
3441 
3442             // Now trigger connection to the last saved network.
3443             WifiConfiguration savedNetworkToConnect =
3444                     savedNetworks.get(savedNetworks.size() - 1);
3445             synchronized (mLock) {
3446                 try {
3447                     if (withNetworkId) {
3448                         sWifiManager.connect(savedNetworkToConnect.networkId, actionListener);
3449                     } else {
3450                         sWifiManager.connect(savedNetworkToConnect, actionListener);
3451                     }
3452                     // now wait for callback
3453                     mLock.wait(TEST_WAIT_DURATION_MS);
3454                 } catch (InterruptedException e) {
3455                 }
3456             }
3457             // check if we got the success callback
3458             assertTrue(actionListener.onSuccessCalled);
3459             // Wait for connection to complete & ensure we are connected to the saved network.
3460             waitForConnection();
3461             assertEquals(savedNetworkToConnect.networkId,
3462                     sWifiManager.getConnectionInfo().getNetworkId());
3463         } finally {
3464             // Re-enable all saved networks before exiting.
3465             if (savedNetworks != null) {
3466                 for (WifiConfiguration network : savedNetworks) {
3467                     sWifiManager.enableNetwork(network.networkId, true);
3468                 }
3469             }
3470             uiAutomation.dropShellPermissionIdentity();
3471         }
3472     }
3473 
3474     /**
3475      * Tests {@link WifiManager#connect(int, WifiManager.ActionListener)} to an existing saved
3476      * network.
3477      */
3478     @Test
testConnectWithNetworkId()3479     public void testConnectWithNetworkId() throws Exception {
3480         testConnect(true);
3481     }
3482 
3483     /**
3484      * Tests {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)} to an
3485      * existing saved network.
3486      */
3487     @Test
testConnectWithWifiConfiguration()3488     public void testConnectWithWifiConfiguration() throws Exception {
3489         testConnect(false);
3490 
3491     }
3492 
3493     private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
3494         private final Object mLock;
3495         public boolean onAvailableCalled = false;
3496         public Network network;
3497         public NetworkCapabilities networkCapabilities;
3498 
TestNetworkCallback(Object lock)3499         TestNetworkCallback(Object lock) {
3500             mLock = lock;
3501         }
3502 
3503         @Override
onAvailable(Network network)3504         public void onAvailable(Network network) {
3505             synchronized (mLock) {
3506                 onAvailableCalled = true;
3507                 this.network = network;
3508             }
3509         }
3510 
3511         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)3512         public void onCapabilitiesChanged(Network network,
3513                 NetworkCapabilities networkCapabilities) {
3514             synchronized (mLock) {
3515                 this.networkCapabilities = networkCapabilities;
3516                 mLock.notify();
3517             }
3518         }
3519     }
3520 
waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered)3521     private void waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered) {
3522         Object lock = new Object();
3523         TestNetworkCallback networkCallbackListener = new TestNetworkCallback(lock);
3524         synchronized (lock) {
3525             try {
3526                 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder()
3527                         .addTransportType(TRANSPORT_WIFI);
3528                 if (expectMetered) {
3529                     networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_METERED);
3530                 } else {
3531                     networkRequestBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
3532                 }
3533                 // File a request for wifi network.
3534                 sConnectivityManager.registerNetworkCallback(
3535                         networkRequestBuilder.build(), networkCallbackListener);
3536                 // now wait for callback
3537                 lock.wait(TEST_WAIT_DURATION_MS);
3538             } catch (InterruptedException e) {
3539             }
3540         }
3541         assertTrue(networkCallbackListener.onAvailableCalled);
3542     }
3543 
3544     /**
3545      * Tests {@link WifiManager#save(WifiConfiguration, WifiManager.ActionListener)} by marking
3546      * an existing saved network metered.
3547      */
3548     @Test
testSave()3549     public void testSave() throws Exception {
3550         Object lock = new Object();
3551         TestActionListener actionListener = new TestActionListener(lock);
3552         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3553         List<WifiConfiguration> savedNetworks = null;
3554         WifiConfiguration currentConfig = null;
3555         try {
3556             uiAutomation.adoptShellPermissionIdentity();
3557             // These below API's only work with privileged permissions (obtained via shell identity
3558             // for test)
3559 
3560             WifiInfo wifiInfo = sWifiManager.getConnectionInfo();
3561             savedNetworks = sWifiManager.getConfiguredNetworks();
3562 
3563             // find the current network's WifiConfiguration
3564             currentConfig = savedNetworks
3565                     .stream()
3566                     .filter(config -> config.networkId == wifiInfo.getNetworkId())
3567                     .findAny()
3568                     .get();
3569 
3570             // Ensure that the current network is not metered.
3571             assertNotEquals("Ensure that the saved network is configured as unmetered",
3572                     currentConfig.meteredOverride,
3573                     WifiConfiguration.METERED_OVERRIDE_METERED);
3574 
3575             // Disable all except the currently connected networks to avoid reconnecting to the
3576             // wrong network after later setting the current network as metered.
3577             for (WifiConfiguration network : savedNetworks) {
3578                 if (network.networkId != currentConfig.networkId) {
3579                     assertTrue(sWifiManager.disableNetwork(network.networkId));
3580                 }
3581             }
3582 
3583             // Check the network capabilities to ensure that the network is marked not metered.
3584             waitForNetworkCallbackAndCheckForMeteredness(false);
3585 
3586             // Now mark the network metered and save.
3587             synchronized (lock) {
3588                 try {
3589                     WifiConfiguration modSavedNetwork = new WifiConfiguration(currentConfig);
3590                     modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
3591                     sWifiManager.save(modSavedNetwork, actionListener);
3592                     // now wait for callback
3593                     lock.wait(TEST_WAIT_DURATION_MS);
3594                 } catch (InterruptedException e) {
3595                 }
3596             }
3597             // check if we got the success callback
3598             assertTrue(actionListener.onSuccessCalled);
3599             // Ensure we disconnected on marking the network metered & connect back.
3600             waitForDisconnection();
3601             waitForConnection();
3602             // Check the network capabilities to ensure that the network is marked metered now.
3603             waitForNetworkCallbackAndCheckForMeteredness(true);
3604 
3605         } finally {
3606             // Restore original network config (restore the meteredness back);
3607             if (currentConfig != null) {
3608                 sWifiManager.updateNetwork(currentConfig);
3609             }
3610             // re-enable all networks
3611             if (savedNetworks != null) {
3612                 for (WifiConfiguration network : savedNetworks) {
3613                     sWifiManager.enableNetwork(network.networkId, true);
3614                 }
3615             }
3616             uiAutomation.dropShellPermissionIdentity();
3617         }
3618     }
3619 
3620     /**
3621      * Tests {@link WifiManager#forget(int, WifiManager.ActionListener)} by adding/removing a new
3622      * network.
3623      */
3624     @AsbSecurityTest(cveBugId = 159373687)
3625     @Test
testForget()3626     public void testForget() throws Exception {
3627         TestActionListener actionListener = new TestActionListener(mLock);
3628         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3629         int newNetworkId = INVALID_NETWORK_ID;
3630         try {
3631             uiAutomation.adoptShellPermissionIdentity();
3632             // These below API's only work with privileged permissions (obtained via shell identity
3633             // for test)
3634             List<WifiConfiguration> savedNetworks = sWifiManager.getConfiguredNetworks();
3635 
3636             WifiConfiguration newOpenNetwork = new WifiConfiguration();
3637             newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\"";
3638             newNetworkId = sWifiManager.addNetwork(newOpenNetwork);
3639             assertNotEquals(INVALID_NETWORK_ID, newNetworkId);
3640 
3641             // Multi-type configurations might be converted to more than 1 configuration.
3642             assertThat(savedNetworks.size() < sWifiManager.getConfiguredNetworks().size()).isTrue();
3643 
3644             // Need an effectively-final holder because we need to modify inner Intent in callback.
3645             class IntentHolder {
3646                 Intent intent;
3647             }
3648             IntentHolder intentHolder = new IntentHolder();
3649             sContext.registerReceiver(new BroadcastReceiver() {
3650                 @Override
3651                 public void onReceive(Context context, Intent intent) {
3652                     Log.i(TAG, "Received CONFIGURED_NETWORKS_CHANGED_ACTION broadcast: " + intent);
3653                     intentHolder.intent = intent;
3654                 }
3655             }, new IntentFilter(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION));
3656 
3657             // Now remove the network
3658             synchronized (mLock) {
3659                 try {
3660                     sWifiManager.forget(newNetworkId, actionListener);
3661                     // now wait for callback
3662                     mLock.wait(TEST_WAIT_DURATION_MS);
3663                 } catch (InterruptedException e) {
3664                 }
3665             }
3666             // check if we got the success callback
3667             assertTrue(actionListener.onSuccessCalled);
3668 
3669             PollingCheck.check(
3670                     "Didn't receive CONFIGURED_NETWORKS_CHANGED_ACTION broadcast!",
3671                     TEST_WAIT_DURATION_MS,
3672                     () -> intentHolder.intent != null);
3673             Intent intent = intentHolder.intent;
3674             assertEquals(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION, intent.getAction());
3675             assertTrue(intent.getBooleanExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false));
3676             assertEquals(WifiManager.CHANGE_REASON_REMOVED,
3677                     intent.getIntExtra(WifiManager.EXTRA_CHANGE_REASON, -1));
3678             assertNull(intent.getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION));
3679 
3680             // Ensure that the new network has been successfully removed.
3681             assertEquals(savedNetworks.size(), sWifiManager.getConfiguredNetworks().size());
3682         } finally {
3683             // For whatever reason, if the forget fails, try removing using the public remove API.
3684             if (newNetworkId != INVALID_NETWORK_ID) sWifiManager.removeNetwork(newNetworkId);
3685             uiAutomation.dropShellPermissionIdentity();
3686         }
3687     }
3688 
3689     /**
3690      * Tests {@link WifiManager#getFactoryMacAddresses()} returns at least one valid MAC address.
3691      */
3692     @RequiresDevice
3693     @Test
testGetFactoryMacAddresses()3694     public void testGetFactoryMacAddresses() throws Exception {
3695         TestActionListener actionListener = new TestActionListener(mLock);
3696         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3697         int newNetworkId = INVALID_NETWORK_ID;
3698         try {
3699             uiAutomation.adoptShellPermissionIdentity();
3700             // Obtain the factory MAC address
3701             String[] macAddresses = sWifiManager.getFactoryMacAddresses();
3702             assertTrue("At list one MAC address should be returned.", macAddresses.length > 0);
3703             try {
3704                 MacAddress mac = MacAddress.fromString(macAddresses[0]);
3705                 assertNotEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mac);
3706                 assertFalse(MacAddressUtils.isMulticastAddress(mac));
3707             } catch (IllegalArgumentException e) {
3708                 fail("Factory MAC address is invalid");
3709             }
3710         } finally {
3711             uiAutomation.dropShellPermissionIdentity();
3712         }
3713     }
3714 
3715     /**
3716      * Tests {@link WifiManager#isApMacRandomizationSupported()} does not crash.
3717      */
3718     @Test
testIsApMacRandomizationSupported()3719     public void testIsApMacRandomizationSupported() throws Exception {
3720         sWifiManager.isApMacRandomizationSupported();
3721     }
3722 
3723     /**
3724      * Tests {@link WifiManager#isConnectedMacRandomizationSupported()} does not crash.
3725      */
3726     @Test
testIsConnectedMacRandomizationSupported()3727     public void testIsConnectedMacRandomizationSupported() throws Exception {
3728         sWifiManager.isConnectedMacRandomizationSupported();
3729     }
3730 
3731     /**
3732      * Tests {@link WifiManager#isPreferredNetworkOffloadSupported()} does not crash.
3733      */
3734     @Test
testIsPreferredNetworkOffloadSupported()3735     public void testIsPreferredNetworkOffloadSupported() throws Exception {
3736         sWifiManager.isPreferredNetworkOffloadSupported();
3737     }
3738 
3739     /** Test that PNO scans reconnects us when the device is disconnected and the screen is off. */
3740     @Test
testPnoScan()3741     public void testPnoScan() throws Exception {
3742         if (!sWifiManager.isPreferredNetworkOffloadSupported()) {
3743             // skip the test if PNO scanning is not supported
3744             return;
3745         }
3746 
3747         WifiInfo currentNetwork = ShellIdentityUtils.invokeWithShellPermissions(
3748                 sWifiManager::getConnectionInfo);
3749 
3750         // disable all networks that aren't already disabled
3751         List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
3752                 sWifiManager::getConfiguredNetworks);
3753         Set<Integer> disabledNetworkIds = new HashSet<>();
3754         for (WifiConfiguration config : savedNetworks) {
3755             if (config.getNetworkSelectionStatus().getNetworkSelectionDisableReason()
3756                     == WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE) {
3757                 ShellIdentityUtils.invokeWithShellPermissions(
3758                         () -> sWifiManager.disableNetwork(config.networkId));
3759                 disabledNetworkIds.add(config.networkId);
3760             }
3761         }
3762 
3763         try {
3764             // wait for disconnection from current network
3765             waitForDisconnection();
3766 
3767             // turn screen off
3768             turnScreenOffNoDelay();
3769 
3770             // re-enable the current network - this will trigger PNO
3771             ShellIdentityUtils.invokeWithShellPermissions(
3772                     () -> sWifiManager.enableNetwork(currentNetwork.getNetworkId(), false));
3773             disabledNetworkIds.remove(currentNetwork.getNetworkId());
3774 
3775             // PNO should reconnect us back to the network we disconnected from
3776             waitForConnection(WIFI_PNO_CONNECT_TIMEOUT_MILLIS);
3777         } finally {
3778             // re-enable disabled networks
3779             for (int disabledNetworkId : disabledNetworkIds) {
3780                 ShellIdentityUtils.invokeWithShellPermissions(
3781                         () -> sWifiManager.enableNetwork(disabledNetworkId, true));
3782             }
3783         }
3784     }
3785 
3786     /**
3787      * Tests {@link WifiManager#isStaApConcurrencySupported()}.
3788      */
3789     @Test
testIsStaApConcurrencySupported()3790     public void testIsStaApConcurrencySupported() throws Exception {
3791         // check that softap mode is supported by the device
3792         assumeTrue(sWifiManager.isPortableHotspotSupported());
3793         // Re-enabled Wi-Fi as shell for HalDeviceManager legacy LOHS behavior when there's no
3794         // STA+AP concurrency.
3795         ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.setWifiEnabled(false));
3796         PollingCheck.check("Wifi turn off failed!", 2_000, () -> !sWifiManager.isWifiEnabled());
3797         SystemUtil.runShellCommand("cmd wifi set-wifi-enabled enabled");
3798         PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS,
3799                 () -> sWifiManager.isWifiEnabled());
3800 
3801         runWithScanning(() -> {
3802             boolean isStaApConcurrencySupported = sWifiManager.isStaApConcurrencySupported();
3803             // start local only hotspot.
3804             TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
3805             try {
3806                 if (isStaApConcurrencySupported) {
3807                     assertTrue(sWifiManager.isWifiEnabled());
3808                 } else {
3809                     // no concurrency, wifi should be disabled.
3810                     assertFalse(sWifiManager.isWifiEnabled());
3811                 }
3812             } finally {
3813                 // clean up local only hotspot no matter if assertion passed or failed
3814                 stopLocalOnlyHotspot(callback, true);
3815             }
3816 
3817             assertTrue(sWifiManager.isWifiEnabled());
3818         }, false);
3819     }
3820 
3821     /**
3822      * state is a bitset, where bit 0 indicates whether there was data in, and bit 1 indicates
3823      * whether there was data out. Only count down on the latch once there was both data in and out.
3824      */
3825     private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback {
3826         public final CountDownLatch latch = new CountDownLatch(1);
3827         private int mAccumulator = 0;
3828 
3829         @Override
onStateChanged(int state)3830         public void onStateChanged(int state) {
3831             mAccumulator |= state;
3832             if (mAccumulator == DATA_ACTIVITY_INOUT) {
3833                 latch.countDown();
3834             }
3835         }
3836     }
3837 
sendTraffic()3838     private void sendTraffic() {
3839         boolean didAnyConnectionSucceed = false;
3840         for (int i = 0; i < 10; i++) {
3841             // Do some network operations
3842             HttpURLConnection connection = null;
3843             try {
3844                 URL url = new URL("http://www.google.com/");
3845                 connection = (HttpURLConnection) url.openConnection();
3846                 connection.setInstanceFollowRedirects(false);
3847                 connection.setConnectTimeout(TEST_WAIT_DURATION_MS);
3848                 connection.setReadTimeout(TEST_WAIT_DURATION_MS);
3849                 connection.setUseCaches(false);
3850                 InputStream stream = connection.getInputStream();
3851                 byte[] bytes = new byte[100];
3852                 int receivedBytes = stream.read(bytes);
3853                 if (receivedBytes > 0) {
3854                     didAnyConnectionSucceed = true;
3855                 }
3856             } catch (Exception e) {
3857                 // ignore
3858             } finally {
3859                 if (connection != null) connection.disconnect();
3860             }
3861         }
3862         assertTrue("All connections failed!", didAnyConnectionSucceed);
3863     }
3864 
3865     /**
3866      * Tests {@link WifiManager#registerTrafficStateCallback(Executor,
3867      * WifiManager.TrafficStateCallback)} by sending some traffic.
3868      */
3869     @Test
testTrafficStateCallback()3870     public void testTrafficStateCallback() throws Exception {
3871         TestTrafficStateCallback callback = new TestTrafficStateCallback();
3872         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3873         try {
3874             uiAutomation.adoptShellPermissionIdentity();
3875 
3876             // Turn screen on for wifi traffic polling.
3877             turnScreenOn();
3878             sWifiManager.registerTrafficStateCallback(
3879                     Executors.newSingleThreadExecutor(), callback);
3880             // Send some traffic to trigger the traffic state change callbacks.
3881             sendTraffic();
3882             // now wait for callback
3883             boolean success = callback.latch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS);
3884             // check if we got the state changed callback with both data in and out
3885             assertTrue(success);
3886         } finally {
3887             turnScreenOff();
3888             sWifiManager.unregisterTrafficStateCallback(callback);
3889             uiAutomation.dropShellPermissionIdentity();
3890         }
3891     }
3892 
3893     /**
3894      * Tests {@link WifiManager#setScanAlwaysAvailable(boolean)} &
3895      * {@link WifiManager#isScanAlwaysAvailable()}.
3896      */
3897     @Test
testScanAlwaysAvailable()3898     public void testScanAlwaysAvailable() throws Exception {
3899         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3900         Boolean currState = null;
3901         try {
3902             uiAutomation.adoptShellPermissionIdentity();
3903             currState = sWifiManager.isScanAlwaysAvailable();
3904             boolean newState = !currState;
3905             sWifiManager.setScanAlwaysAvailable(newState);
3906             PollingCheck.check(
3907                     "Wifi scanning toggle failed!",
3908                     DURATION_SETTINGS_TOGGLE,
3909                     () -> sWifiManager.isScanAlwaysAvailable() == newState);
3910             assertEquals(newState, sWifiManager.isScanAlwaysAvailable());
3911         } finally {
3912             if (currState != null) sWifiManager.setScanAlwaysAvailable(currState);
3913             uiAutomation.dropShellPermissionIdentity();
3914         }
3915     }
3916 
3917     /**
3918      * Tests {@link WifiManager#setScanThrottleEnabled(boolean)} &
3919      * {@link WifiManager#isScanThrottleEnabled()}.
3920      */
3921     @Test
testScanThrottleEnabled()3922     public void testScanThrottleEnabled() throws Exception {
3923         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3924         Boolean currState = null;
3925         try {
3926             uiAutomation.adoptShellPermissionIdentity();
3927             currState = sWifiManager.isScanThrottleEnabled();
3928             boolean newState = !currState;
3929             sWifiManager.setScanThrottleEnabled(newState);
3930             PollingCheck.check(
3931                     "Wifi settings toggle failed!",
3932                     DURATION_SETTINGS_TOGGLE,
3933                     () -> sWifiManager.isScanThrottleEnabled() == newState);
3934             assertEquals(newState, sWifiManager.isScanThrottleEnabled());
3935         } finally {
3936             if (currState != null) sWifiManager.setScanThrottleEnabled(currState);
3937             uiAutomation.dropShellPermissionIdentity();
3938         }
3939     }
3940 
3941     /**
3942      * Tests {@link WifiManager#setAutoWakeupEnabled(boolean)} &
3943      * {@link WifiManager#isAutoWakeupEnabled()}.
3944      */
3945     @Test
testAutoWakeUpEnabled()3946     public void testAutoWakeUpEnabled() throws Exception {
3947         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3948         Boolean currState = null;
3949         try {
3950             uiAutomation.adoptShellPermissionIdentity();
3951             currState = sWifiManager.isAutoWakeupEnabled();
3952             boolean newState = !currState;
3953             sWifiManager.setAutoWakeupEnabled(newState);
3954             PollingCheck.check(
3955                     "Wifi settings toggle failed!",
3956                     DURATION_SETTINGS_TOGGLE,
3957                     () -> sWifiManager.isAutoWakeupEnabled() == newState);
3958             assertEquals(newState, sWifiManager.isAutoWakeupEnabled());
3959         } finally {
3960             if (currState != null) sWifiManager.setAutoWakeupEnabled(currState);
3961             uiAutomation.dropShellPermissionIdentity();
3962         }
3963     }
3964 
3965     /**
3966      * Tests {@link WifiManager#setVerboseLoggingEnabled(boolean)} &
3967      * {@link WifiManager#isVerboseLoggingEnabled()}.
3968      */
3969     @Test
testVerboseLoggingEnabled()3970     public void testVerboseLoggingEnabled() throws Exception {
3971         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
3972         Boolean currState = null;
3973         TestWifiVerboseLoggingStatusChangedListener listener =
3974                 WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)
3975                         ? new TestWifiVerboseLoggingStatusChangedListener() : null;
3976         try {
3977             uiAutomation.adoptShellPermissionIdentity();
3978             if (listener != null) {
3979                 sWifiManager.addWifiVerboseLoggingStatusChangedListener(mExecutor, listener);
3980             }
3981             currState = sWifiManager.isVerboseLoggingEnabled();
3982             boolean newState = !currState;
3983             if (listener != null) {
3984                 assertEquals(0, listener.numCalls);
3985             }
3986             sWifiManager.setVerboseLoggingEnabled(newState);
3987             PollingCheck.check(
3988                     "Wifi verbose logging toggle failed!",
3989                     DURATION_SETTINGS_TOGGLE,
3990                     () -> sWifiManager.isVerboseLoggingEnabled() == newState);
3991             if (listener != null) {
3992                 PollingCheck.check(
3993                         "Verbose logging listener timeout",
3994                         DURATION_SETTINGS_TOGGLE,
3995                         () -> listener.status == newState && listener.numCalls == 1);
3996             }
3997         } finally {
3998             if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState);
3999             if (listener != null) {
4000                 sWifiManager.removeWifiVerboseLoggingStatusChangedListener(listener);
4001             }
4002             uiAutomation.dropShellPermissionIdentity();
4003         }
4004     }
4005 
4006     /**
4007      * Tests {@link WifiManager#setVerboseLoggingLevel(int)}.
4008      */
4009     @Test
testSetVerboseLogging()4010     public void testSetVerboseLogging() throws Exception {
4011         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4012         Boolean currState = null;
4013         try {
4014             uiAutomation.adoptShellPermissionIdentity();
4015             currState = sWifiManager.isVerboseLoggingEnabled();
4016 
4017             sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED);
4018             assertTrue(sWifiManager.isVerboseLoggingEnabled());
4019             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED,
4020                     sWifiManager.getVerboseLoggingLevel());
4021 
4022             sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED);
4023             assertFalse(sWifiManager.isVerboseLoggingEnabled());
4024             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED,
4025                     sWifiManager.getVerboseLoggingLevel());
4026         } finally {
4027             if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState);
4028             uiAutomation.dropShellPermissionIdentity();
4029         }
4030     }
4031 
4032     /**
4033      * Test {@link WifiManager#setVerboseLoggingLevel(int)} for show key mode.
4034      */
4035     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
4036     @Test
testSetVerboseLoggingShowKeyModeNonUserBuild()4037     public void testSetVerboseLoggingShowKeyModeNonUserBuild() throws Exception {
4038         if (Build.TYPE.equals("user")) return;
4039         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4040         Boolean currState = null;
4041         try {
4042             uiAutomation.adoptShellPermissionIdentity();
4043             currState = sWifiManager.isVerboseLoggingEnabled();
4044 
4045             sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY);
4046             assertTrue(sWifiManager.isVerboseLoggingEnabled());
4047             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY,
4048                     sWifiManager.getVerboseLoggingLevel());
4049         } finally {
4050             if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState);
4051             uiAutomation.dropShellPermissionIdentity();
4052         }
4053     }
4054 
4055     /**
4056      * Test {@link WifiManager#setVerboseLoggingLevel(int)} for show key mode.
4057      */
4058     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
4059     @Test
testSetVerboseLoggingShowKeyModeUserBuild()4060     public void testSetVerboseLoggingShowKeyModeUserBuild() throws Exception {
4061         if (!Build.TYPE.equals("user")) return;
4062         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4063         Boolean currState = null;
4064         try {
4065             uiAutomation.adoptShellPermissionIdentity();
4066             currState = sWifiManager.isVerboseLoggingEnabled();
4067 
4068             sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY);
4069             assertTrue(sWifiManager.isVerboseLoggingEnabled());
4070             assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY,
4071                     sWifiManager.getVerboseLoggingLevel());
4072             fail("Verbosing logging show key mode should not be allowed for user build.");
4073         } catch (SecurityException e) {
4074             // expected
4075         } finally {
4076             if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState);
4077             uiAutomation.dropShellPermissionIdentity();
4078         }
4079     }
4080 
4081     /**
4082      * Tests {@link WifiManager#factoryReset()} cannot be invoked from a non-privileged app.
4083      *
4084      * Note: This intentionally does not test the full reset functionality because it causes
4085      * the existing saved networks on the device to be lost after the test. If you add the
4086      * networks back after reset, the ownership of saved networks will change.
4087      */
4088     @Test
testFactoryReset()4089     public void testFactoryReset() throws Exception {
4090         List<WifiConfiguration> beforeSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
4091                 sWifiManager::getConfiguredNetworks);
4092         try {
4093             sWifiManager.factoryReset();
4094             fail("Factory reset should not be allowed for non-privileged apps");
4095         } catch (SecurityException e) {
4096             // expected
4097         }
4098         List<WifiConfiguration> afterSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
4099                 sWifiManager::getConfiguredNetworks);
4100         assertEquals(beforeSavedNetworks.size(), afterSavedNetworks.size());
4101     }
4102 
4103     /**
4104      * Test {@link WifiNetworkConnectionStatistics} does not crash.
4105      * TODO(b/150891569): deprecate it in Android S, this API is not used anywhere.
4106      */
4107     @Test
testWifiNetworkConnectionStatistics()4108     public void testWifiNetworkConnectionStatistics() {
4109         new WifiNetworkConnectionStatistics();
4110         WifiNetworkConnectionStatistics stats = new WifiNetworkConnectionStatistics(0, 0);
4111         new WifiNetworkConnectionStatistics(stats);
4112     }
4113 
4114     /**
4115      * Verify that startRestrictingAutoJoinToSubscriptionId disconnects wifi and disables
4116      * auto-connect to non-carrier-merged networks. Then verify that
4117      * stopRestrictingAutoJoinToSubscriptionId makes the disabled networks clear to connect
4118      * again.
4119      */
4120     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
4121     @Test
testStartAndStopRestrictingAutoJoinToSubscriptionId()4122     public void testStartAndStopRestrictingAutoJoinToSubscriptionId() throws Exception {
4123         int fakeSubscriptionId = 5;
4124         ShellIdentityUtils.invokeWithShellPermissions(() ->
4125                 sWifiManager.startRestrictingAutoJoinToSubscriptionId(fakeSubscriptionId));
4126         waitForDisconnection();
4127         startScan();
4128         ensureNotConnected();
4129         ShellIdentityUtils.invokeWithShellPermissions(() ->
4130                 sWifiManager.stopRestrictingAutoJoinToSubscriptionId());
4131         startScan();
4132         waitForConnection();
4133     }
4134 
4135     private class TestActiveCountryCodeChangedCallback implements
4136             WifiManager.ActiveCountryCodeChangedCallback  {
4137         private String mCurrentCountryCode;
4138         private boolean mIsOnActiveCountryCodeChangedCalled = false;
4139         private boolean mIsOnCountryCodeInactiveCalled = false;
4140 
isOnActiveCountryCodeChangedCalled()4141         public boolean isOnActiveCountryCodeChangedCalled() {
4142             return mIsOnActiveCountryCodeChangedCalled;
4143         }
4144 
isOnCountryCodeInactiveCalled()4145         public boolean isOnCountryCodeInactiveCalled() {
4146             return mIsOnCountryCodeInactiveCalled;
4147         }
resetCallbackCallededHistory()4148         public void resetCallbackCallededHistory() {
4149             mIsOnActiveCountryCodeChangedCalled = false;
4150             mIsOnCountryCodeInactiveCalled = false;
4151         }
4152 
getCurrentDriverCountryCode()4153         public String getCurrentDriverCountryCode() {
4154             return mCurrentCountryCode;
4155         }
4156 
4157         @Override
onActiveCountryCodeChanged(String country)4158         public void onActiveCountryCodeChanged(String country) {
4159             Log.d(TAG, "Receive DriverCountryCodeChanged to " + country);
4160             mCurrentCountryCode = country;
4161             mIsOnActiveCountryCodeChangedCalled = true;
4162         }
4163 
4164         @Override
onCountryCodeInactive()4165         public void onCountryCodeInactive() {
4166             Log.d(TAG, "Receive onCountryCodeInactive");
4167             mCurrentCountryCode = null;
4168             mIsOnCountryCodeInactiveCalled = true;
4169         }
4170     }
4171 
4172     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
4173     @Test
testActiveCountryCodeChangedCallback()4174     public void testActiveCountryCodeChangedCallback() throws Exception {
4175         if (!hasLocationFeature()) {
4176             // skip the test if location is not supported
4177             return;
4178         }
4179         if (!isLocationEnabled()) {
4180             fail("Please enable location for this test - since country code is not available"
4181                     + " when location is disabled!");
4182         }
4183         if (shouldSkipCountryCodeDependentTest()) {
4184             // skip the test when there is no Country Code available
4185             return;
4186         }
4187         if (!PropertyUtil.isVndkApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)) {
4188             // skip the test if vendor version is lower than T
4189             return;
4190         }
4191         TestActiveCountryCodeChangedCallback testCountryCodeChangedCallback =
4192                 new TestActiveCountryCodeChangedCallback();
4193         TestExecutor executor = new TestExecutor();
4194         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4195         try {
4196             // Run with scanning disable to make sure there is no active mode.
4197             runWithScanning(() -> {
4198                 uiAutomation.adoptShellPermissionIdentity();
4199                 turnOffWifiAndTetheredHotspotIfEnabled();
4200                 sWifiManager.registerActiveCountryCodeChangedCallback(
4201                         executor, testCountryCodeChangedCallback);
4202 
4203 
4204                 PollingCheck.check(
4205                         "DriverCountryCode is non-null when wifi off",
4206                         5000,
4207                         () -> {
4208                             executor.runAll();
4209                             return testCountryCodeChangedCallback
4210                                         .isOnCountryCodeInactiveCalled()
4211                                     && testCountryCodeChangedCallback.getCurrentDriverCountryCode()
4212                                             == null;
4213                         });
4214                 // Enable wifi to make sure country code has been updated.
4215                 sWifiManager.setWifiEnabled(true);
4216                 PollingCheck.check(
4217                         "DriverCountryCode is null when wifi on",
4218                         5000,
4219                         () -> {
4220                             executor.runAll();
4221                             return testCountryCodeChangedCallback
4222                                         .isOnActiveCountryCodeChangedCalled()
4223                                     && testCountryCodeChangedCallback.getCurrentDriverCountryCode()
4224                                             != null;
4225                         });
4226                 // Disable wifi to trigger country code change
4227                 sWifiManager.setWifiEnabled(false);
4228                 PollingCheck.check(
4229                         "DriverCountryCode should be null when wifi off",
4230                         5000,
4231                         () -> {
4232                             executor.runAll();
4233                             return testCountryCodeChangedCallback.isOnCountryCodeInactiveCalled()
4234                                     && testCountryCodeChangedCallback
4235                                             .getCurrentDriverCountryCode() == null;
4236                         });
4237                 sWifiManager.unregisterActiveCountryCodeChangedCallback(
4238                             testCountryCodeChangedCallback);
4239                 testCountryCodeChangedCallback.resetCallbackCallededHistory();
4240                 sWifiManager.setWifiEnabled(true);
4241                 // Check there is no callback has been called.
4242                 PollingCheck.check(
4243                         "Callback is called after unregister",
4244                         5000,
4245                         () -> {
4246                             executor.runAll();
4247                             return !testCountryCodeChangedCallback.isOnCountryCodeInactiveCalled()
4248                                     && !testCountryCodeChangedCallback
4249                                             .isOnActiveCountryCodeChangedCalled();
4250                         });
4251             }, false /* Run with disabled */);
4252         } finally {
4253             uiAutomation.dropShellPermissionIdentity();
4254         }
4255     }
4256 
4257     /**
4258      * Test that the wifi country code is either null, or a length-2 string.
4259      */
4260     @Test
testGetCountryCode()4261     public void testGetCountryCode() throws Exception {
4262         String wifiCountryCode = ShellIdentityUtils.invokeWithShellPermissions(
4263                 sWifiManager::getCountryCode);
4264 
4265         if (wifiCountryCode == null) {
4266             return;
4267         }
4268         assertEquals(2, wifiCountryCode.length());
4269 
4270         // assert that the country code is all uppercase
4271         assertEquals(wifiCountryCode.toUpperCase(Locale.US), wifiCountryCode);
4272 
4273         // skip if Telephony is unsupported
4274         if (!WifiFeature.isTelephonySupported(sContext)) {
4275             return;
4276         }
4277 
4278         String telephonyCountryCode = sContext.getSystemService(TelephonyManager.class)
4279                 .getNetworkCountryIso();
4280 
4281         // skip if Telephony country code is unavailable
4282         if (telephonyCountryCode == null || telephonyCountryCode.isEmpty()) {
4283             return;
4284         }
4285 
4286         assertEquals(telephonyCountryCode, wifiCountryCode.toLowerCase(Locale.US));
4287     }
4288 
4289     /**
4290      * Helper function to test getCurrentNetwork
4291      * @param shouldDisableWifi true to disable wifi, false to disconnect
4292      * @throws Exception
4293      */
testGetCurrentNetwork(boolean shouldDisableWifi)4294     private void testGetCurrentNetwork(boolean shouldDisableWifi) throws Exception {
4295         // ensure Wifi is connected
4296         ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.reconnect());
4297         PollingCheck.check(
4298                 "Connection info network id is invalid - Please ensure there is a " +
4299                 " saved network in range of this device",
4300                 WIFI_CONNECT_TIMEOUT_MILLIS,
4301                 () -> sWifiManager.getConnectionInfo().getNetworkId() != -1);
4302         PollingCheck.check(
4303                 "Wifi current network is null - Please ensure there is a saved network " +
4304                         " in range of this device",
4305                 WIFI_CONNECT_TIMEOUT_MILLIS,
4306                 () -> ShellIdentityUtils.invokeWithShellPermissions(sWifiManager::getCurrentNetwork)
4307                         != null);
4308 
4309         String networkKey = sWifiManager.getConnectionInfo().getNetworkKey();
4310         assertNotNull(networkKey);
4311 
4312         Network wifiCurrentNetwork = ShellIdentityUtils.invokeWithShellPermissions(
4313                 sWifiManager::getCurrentNetwork);
4314         assertNotNull(wifiCurrentNetwork);
4315 
4316         List<WifiConfiguration> configuredNetwork = ShellIdentityUtils.invokeWithShellPermissions(
4317                 sWifiManager::getConfiguredNetworks);
4318 
4319         boolean isNetworkKeyExist = false;
4320         for (WifiConfiguration config : configuredNetwork) {
4321             if (config.getAllNetworkKeys().contains(networkKey)) {
4322                 isNetworkKeyExist = true;
4323                 break;
4324             }
4325         }
4326 
4327         assertTrue(isNetworkKeyExist);
4328 
4329         TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock);
4330         synchronized (mLock) {
4331             try {
4332                 // File a request for wifi network.
4333                 sConnectivityManager.registerNetworkCallback(
4334                         new NetworkRequest.Builder()
4335                                 .addTransportType(TRANSPORT_WIFI)
4336                                 .build(),
4337                         networkCallbackListener);
4338                 // now wait for callback
4339                 mLock.wait(TEST_WAIT_DURATION_MS);
4340             } catch (InterruptedException e) {
4341             }
4342         }
4343         assertTrue(networkCallbackListener.onAvailableCalled);
4344         Network connectivityCurrentNetwork = networkCallbackListener.network;
4345         assertEquals(connectivityCurrentNetwork, wifiCurrentNetwork);
4346 
4347         if (shouldDisableWifi) {
4348             setWifiEnabled(false);
4349             PollingCheck.check(
4350                     "Wifi not disabled!",
4351                     20000,
4352                     () -> !sWifiManager.isWifiEnabled());
4353         } else {
4354             ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.disconnect());
4355         }
4356         PollingCheck.check(
4357                 "Wifi not disconnected! Connection info network id still valid",
4358                 20000,
4359                 () -> sWifiManager.getConnectionInfo().getNetworkId() == -1);
4360 
4361         PollingCheck.check(
4362                 "Wifi not disconnected! Current network is not null",
4363                 WIFI_CONNECT_TIMEOUT_MILLIS,
4364                 () -> ShellIdentityUtils.invokeWithShellPermissions(sWifiManager::getCurrentNetwork)
4365                         == null);
4366     }
4367 
4368     /**
4369      * Test that {@link WifiManager#getCurrentNetwork()} returns a Network object consistent
4370      * with {@link ConnectivityManager#registerNetworkCallback} when connected to a Wifi network,
4371      * and returns null when disconnected.
4372      */
4373     @Test
testGetCurrentNetworkWifiDisconnected()4374     public void testGetCurrentNetworkWifiDisconnected() throws Exception {
4375         testGetCurrentNetwork(false);
4376     }
4377 
4378     /**
4379      * Test that {@link WifiManager#getCurrentNetwork()} returns a Network object consistent
4380      * with {@link ConnectivityManager#registerNetworkCallback} when connected to a Wifi network,
4381      * and returns null when wifi disabled.
4382      */
4383     @Test
testGetCurrentNetworkWifiDisabled()4384     public void testGetCurrentNetworkWifiDisabled() throws Exception {
4385         testGetCurrentNetwork(true);
4386     }
4387 
4388     /**
4389      * Tests {@link WifiManager#isWpa3SaeSupported()} does not crash.
4390      */
4391     @Test
testIsWpa3SaeSupported()4392     public void testIsWpa3SaeSupported() throws Exception {
4393         sWifiManager.isWpa3SaeSupported();
4394     }
4395 
4396     /**
4397      * Tests {@link WifiManager#isWpa3SuiteBSupported()} does not crash.
4398      */
4399     @Test
testIsWpa3SuiteBSupported()4400     public void testIsWpa3SuiteBSupported() throws Exception {
4401         sWifiManager.isWpa3SuiteBSupported();
4402     }
4403 
4404     /**
4405      * Tests {@link WifiManager#isEnhancedOpenSupported()} does not crash.
4406      */
4407     @Test
testIsEnhancedOpenSupported()4408     public void testIsEnhancedOpenSupported() throws Exception {
4409         sWifiManager.isEnhancedOpenSupported();
4410     }
4411 
4412     /**
4413      * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in
4414      * both WiFi enabled/disabled states.
4415      * Note that the response depends on device support and hence both true/false
4416      * are valid responses.
4417      */
4418     @Test
testIs5GhzBandSupported()4419     public void testIs5GhzBandSupported() throws Exception {
4420         // Check for 5GHz support with wifi enabled
4421         setWifiEnabled(true);
4422         PollingCheck.check(
4423                 "Wifi not enabled!",
4424                 20000,
4425                 () -> sWifiManager.isWifiEnabled());
4426         boolean isSupportedEnabled = sWifiManager.is5GHzBandSupported();
4427 
4428         // Check for 5GHz support with wifi disabled
4429         setWifiEnabled(false);
4430         PollingCheck.check(
4431                 "Wifi not disabled!",
4432                 20000,
4433                 () -> !sWifiManager.isWifiEnabled());
4434         boolean isSupportedDisabled = sWifiManager.is5GHzBandSupported();
4435 
4436         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
4437         // Note, the reverse is a valid case.
4438         if (isSupportedDisabled) {
4439             assertTrue(isSupportedEnabled);
4440         }
4441     }
4442 
4443     /**
4444      * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in
4445      * both Wifi enabled/disabled states.
4446      * Note that the response depends on device support and hence both true/false
4447      * are valid responses.
4448      */
4449     @Test
testIs6GhzBandSupported()4450     public void testIs6GhzBandSupported() throws Exception {
4451         // Check for 6GHz support with wifi enabled
4452         setWifiEnabled(true);
4453         PollingCheck.check(
4454                 "Wifi not enabled!",
4455                 20000,
4456                 () -> sWifiManager.isWifiEnabled());
4457         boolean isSupportedEnabled = sWifiManager.is6GHzBandSupported();
4458 
4459         // Check for 6GHz support with wifi disabled
4460         setWifiEnabled(false);
4461         PollingCheck.check(
4462                 "Wifi not disabled!",
4463                 20000,
4464                 () -> !sWifiManager.isWifiEnabled());
4465         boolean isSupportedDisabled = sWifiManager.is6GHzBandSupported();
4466 
4467         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
4468         // Note, the reverse is a valid case.
4469         if (isSupportedDisabled) {
4470             assertTrue(isSupportedEnabled);
4471         }
4472     }
4473 
4474     /**
4475      * Test that {@link WifiManager#is60GHzBandSupported()} returns successfully in
4476      * both Wifi enabled/disabled states.
4477      * Note that the response depends on device support and hence both true/false
4478      * are valid responses.
4479      */
4480     @Test
testIs60GhzBandSupported()4481     public void testIs60GhzBandSupported() throws Exception {
4482         if (!(WifiFeature.isWifiSupported(sContext)
4483                 && ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S))) {
4484             // skip the test if WiFi is not supported
4485             return;
4486         }
4487 
4488         // Check for 60GHz support with wifi enabled
4489         setWifiEnabled(true);
4490         PollingCheck.check(
4491                 "Wifi not enabled!",
4492                 20000,
4493                 () -> sWifiManager.isWifiEnabled());
4494         boolean isSupportedEnabled = sWifiManager.is60GHzBandSupported();
4495 
4496         // Check for 60GHz support with wifi disabled
4497         setWifiEnabled(false);
4498         PollingCheck.check(
4499                 "Wifi not disabled!",
4500                 20000,
4501                 () -> !sWifiManager.isWifiEnabled());
4502         boolean isSupportedDisabled = sWifiManager.is60GHzBandSupported();
4503 
4504         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
4505         // Note, the reverse is a valid case.
4506         if (isSupportedDisabled) {
4507             assertTrue(isSupportedEnabled);
4508         }
4509     }
4510 
4511     /**
4512      * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in
4513      * both Wifi enabled/disabled states. The test is to be performed on
4514      * {@link WifiAnnotations}'s {@code WIFI_STANDARD_}
4515      * Note that the response depends on device support and hence both true/false
4516      * are valid responses.
4517      */
4518     @Test
testIsWifiStandardsSupported()4519     public void testIsWifiStandardsSupported() throws Exception {
4520         // Check for WiFi standards support with wifi enabled
4521         setWifiEnabled(true);
4522         PollingCheck.check(
4523                 "Wifi not enabled!",
4524                 20000,
4525                 () -> sWifiManager.isWifiEnabled());
4526         boolean isLegacySupportedEnabled =
4527                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
4528         boolean is11nSupporedEnabled =
4529                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
4530         boolean is11acSupportedEnabled =
4531                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
4532         boolean is11axSupportedEnabled =
4533                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
4534         boolean is11beSupportedEnabled =
4535                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE);
4536 
4537         // Check for WiFi standards support with wifi disabled
4538         setWifiEnabled(false);
4539         PollingCheck.check(
4540                 "Wifi not disabled!",
4541                 20000,
4542                 () -> !sWifiManager.isWifiEnabled());
4543 
4544         boolean isLegacySupportedDisabled =
4545                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
4546         boolean is11nSupportedDisabled =
4547                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
4548         boolean is11acSupportedDisabled =
4549                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
4550         boolean is11axSupportedDisabled =
4551                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
4552         boolean is11beSupportedDisabled =
4553                 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE);
4554 
4555         if (isLegacySupportedDisabled) {
4556             assertTrue(isLegacySupportedEnabled);
4557         }
4558 
4559         if (is11nSupportedDisabled) {
4560             assertTrue(is11nSupporedEnabled);
4561         }
4562 
4563         if (is11acSupportedDisabled) {
4564             assertTrue(is11acSupportedEnabled);
4565         }
4566 
4567         if (is11axSupportedDisabled) {
4568             assertTrue(is11axSupportedEnabled);
4569         }
4570 
4571         if (is11beSupportedDisabled) {
4572             assertTrue(is11beSupportedEnabled);
4573         }
4574     }
4575 
createPasspointConfiguration()4576     private static PasspointConfiguration createPasspointConfiguration() {
4577         PasspointConfiguration config = new PasspointConfiguration();
4578         HomeSp homeSp = new HomeSp();
4579         homeSp.setFqdn("test.com");
4580         homeSp.setFriendlyName("friendly name");
4581         homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66});
4582         config.setHomeSp(homeSp);
4583         Credential.SimCredential simCred = new Credential.SimCredential();
4584         simCred.setImsi("123456*");
4585         simCred.setEapType(23 /* EAP_AKA */);
4586         Credential cred = new Credential();
4587         cred.setRealm("realm");
4588         cred.setSimCredential(simCred);
4589         config.setCredential(cred);
4590 
4591         return config;
4592     }
4593 
4594     /**
4595      * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)}
4596      * adds a Passpoint configuration correctly by getting it once it is added, and comparing it
4597      * to the local copy of the configuration.
4598      */
4599     @Test
testAddOrUpdatePasspointConfiguration()4600     public void testAddOrUpdatePasspointConfiguration() throws Exception {
4601         // Create and install a Passpoint configuration
4602         PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
4603         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4604         try {
4605             uiAutomation.adoptShellPermissionIdentity();
4606             sWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
4607 
4608             // Compare configurations
4609             List<PasspointConfiguration> configurations = sWifiManager.getPasspointConfigurations();
4610             assertNotNull("The installed passpoint profile is missing", configurations);
4611             assertEquals(passpointConfiguration, getTargetPasspointConfiguration(configurations,
4612                     passpointConfiguration.getUniqueId()));
4613         } finally {
4614             // Clean up
4615             sWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn());
4616             uiAutomation.dropShellPermissionIdentity();
4617         }
4618     }
4619 
4620     /**
4621      * Tests {@link WifiManager#setPasspointMeteredOverride(String, int)}
4622      * adds a Passpoint configuration correctly, check the default metered setting. Use API change
4623      * metered override, verify Passpoint configuration changes with it.
4624      */
4625     @Test
testSetPasspointMeteredOverride()4626     public void testSetPasspointMeteredOverride() throws Exception {
4627         // Create and install a Passpoint configuration
4628         PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
4629         String fqdn = passpointConfiguration.getHomeSp().getFqdn();
4630         String uniqueId = passpointConfiguration.getUniqueId();
4631         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4632 
4633         try {
4634             uiAutomation.adoptShellPermissionIdentity();
4635             sWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
4636             PasspointConfiguration saved = getTargetPasspointConfiguration(
4637                     sWifiManager.getPasspointConfigurations(), uniqueId);
4638             assertNotNull("The installed passpoint profile is missing", saved);
4639             // Verify meter override setting.
4640             assertEquals("Metered overrider default should be none",
4641                     WifiConfiguration.METERED_OVERRIDE_NONE, saved.getMeteredOverride());
4642             // Change the meter override setting.
4643             sWifiManager.setPasspointMeteredOverride(fqdn,
4644                     WifiConfiguration.METERED_OVERRIDE_METERED);
4645             // Verify passpoint config change with the new setting.
4646             saved = getTargetPasspointConfiguration(
4647                     sWifiManager.getPasspointConfigurations(), uniqueId);
4648             assertNotNull("The installed passpoint profile is missing", saved);
4649             assertEquals("Metered override should be metered",
4650                     WifiConfiguration.METERED_OVERRIDE_METERED, saved.getMeteredOverride());
4651         } finally {
4652             // Clean up
4653             sWifiManager.removePasspointConfiguration(fqdn);
4654             uiAutomation.dropShellPermissionIdentity();
4655         }
4656     }
4657 
4658     /**
4659      * Tests that
4660      * {@link WifiManager#startSubscriptionProvisioning(OsuProvider, Executor, ProvisioningCallback)}
4661      * starts a subscription provisioning, and confirm a status callback invoked once.
4662      */
4663     @Test
testStartSubscriptionProvisioning()4664     public void testStartSubscriptionProvisioning() throws Exception {
4665         // Using Java reflection to construct an OsuProvider instance because its constructor is
4666         // hidden and not available to apps.
4667         Class<?> osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider");
4668         Constructor<?> osuProviderClassConstructor = osuProviderClass.getConstructor(String.class,
4669                 Map.class, String.class, Uri.class, String.class, List.class);
4670 
4671         OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID,
4672                 TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI,
4673                 TEST_METHOD_LIST);
4674         TestProvisioningCallback callback = new TestProvisioningCallback(mLock);
4675         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4676         try {
4677             uiAutomation.adoptShellPermissionIdentity();
4678             synchronized (mLock) {
4679                 // Start a subscription provisioning for a non-existent Passpoint R2 AP
4680                 sWifiManager.startSubscriptionProvisioning(osuProvider, mExecutor, callback);
4681                 mLock.wait(TEST_WAIT_DURATION_MS);
4682             }
4683         } finally {
4684             uiAutomation.dropShellPermissionIdentity();
4685         }
4686         waitForDisconnection();
4687         // Expect only a single callback event, connecting. Since AP doesn't exist, it ends here
4688         assertEquals(ProvisioningCallback.OSU_STATUS_AP_CONNECTING, callback.mProvisioningStatus);
4689         // No failure callbacks expected
4690         assertEquals(0, callback.mProvisioningFailureStatus);
4691         // No completion callback expected
4692         assertFalse(callback.mProvisioningComplete);
4693         ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.setWifiEnabled(false));
4694         PollingCheck.check("Wifi not disabled!", 20000,
4695                 () -> !sWifiManager.isWifiEnabled());
4696     }
4697 
4698     /**
4699      * Tests {@link WifiManager#setTdlsEnabled(InetAddress, boolean)} does not crash.
4700      */
4701     @Test
testSetTdlsEnabled()4702     public void testSetTdlsEnabled() throws Exception {
4703         InetAddress inetAddress = InetAddress.getByName(TEST_IP_ADDRESS);
4704 
4705         sWifiManager.setTdlsEnabled(inetAddress, true);
4706         Thread.sleep(50);
4707         sWifiManager.setTdlsEnabled(inetAddress, false);
4708     }
4709 
4710     /**
4711      * Tests {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean)} does not crash.
4712      */
4713     @Test
testSetTdlsEnabledWithMacAddress()4714     public void testSetTdlsEnabledWithMacAddress() throws Exception {
4715         sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, true);
4716         Thread.sleep(50);
4717         sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, false);
4718     }
4719 
4720     /**
4721      * Verify the usage of {@code WifiManager#isTdlsOperationCurrentlyAvailable}.
4722      */
4723     @Test
testIsTdlsOperationCurrentlyAvailable()4724     public void testIsTdlsOperationCurrentlyAvailable() throws Exception {
4725         boolean expectedResult = sWifiManager.isTdlsSupported();
4726         AtomicBoolean enabled = new AtomicBoolean(false);
4727         sWifiManager.isTdlsOperationCurrentlyAvailable(mExecutor,
4728                 (enabledLocal) -> {
4729                     synchronized (mLock) {
4730                         enabled.set(enabledLocal);
4731                         mLock.notify();
4732                     }
4733                 });
4734         synchronized (mLock) {
4735             mLock.wait(TEST_WAIT_DURATION_MS);
4736         }
4737         assertEquals(expectedResult, enabled.get());
4738     }
4739 
4740     /**
4741      * Verify the usage of {@code WifiManager#getMaxSupportedConcurrentTdlsSessions}.
4742      */
4743     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
4744     @Test
testGetMaxSupportedConcurrentTdlsSessions()4745     public void testGetMaxSupportedConcurrentTdlsSessions() throws Exception {
4746         if (!sWifiManager.isTdlsSupported()) {
4747             // skip the test if TDLS is not supported
4748             return;
4749         }
4750 
4751         AtomicInteger maxNumOfTdlsSessions = new AtomicInteger(0);
4752         sWifiManager.getMaxSupportedConcurrentTdlsSessions(mExecutor,
4753                 (maxNumOfTdlsSessionsLocal) -> {
4754                     synchronized (mLock) {
4755                         maxNumOfTdlsSessions.set(maxNumOfTdlsSessionsLocal);
4756                         mLock.notify();
4757                     }
4758                 });
4759         synchronized (mLock) {
4760             mLock.wait(TEST_WAIT_DURATION_MS);
4761         }
4762         // {@code WifiManager#getMaxSupportedConcurrentTdlsSessions} returns -1
4763         // if HAL doesn't provide this TDLS capability.
4764         assertTrue(maxNumOfTdlsSessions.get() == -1 || maxNumOfTdlsSessions.get() > 0);
4765     }
4766 
4767     /**
4768      * Verify the usage of
4769      * {@link WifiManager#setTdlsEnabled(InetAddress, boolean, Executor, Consumer)}.
4770      */
4771     @Test
testSetTdlsEnabledWithIpAddressConsumerModel()4772     public void testSetTdlsEnabledWithIpAddressConsumerModel() throws Exception {
4773         if (!sWifiManager.isTdlsSupported()) {
4774             // skip the test if TDLS is not supported
4775             return;
4776         }
4777 
4778         InetAddress inetAddress = InetAddress.getByName(TEST_IP_ADDRESS);
4779         sWifiManager.setTdlsEnabled(inetAddress, true, mExecutor, (e) -> {});
4780         sWifiManager.setTdlsEnabled(inetAddress, false, mExecutor, (e) -> {});
4781     }
4782 
4783     /**
4784      * Verify the usage of
4785      * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
4786      * and {@link WifiManager#getNumberOfEnabledTdlsSessions(Executor, Consumer)}.
4787      */
4788     @Test
testSetTdlsEnabledWithMacAddressConsumerModel()4789     public void testSetTdlsEnabledWithMacAddressConsumerModel() throws Exception {
4790         if (!sWifiManager.isTdlsSupported()) {
4791             // skip the test if TDLS is not supported
4792             return;
4793         }
4794 
4795         AtomicBoolean enabled = new AtomicBoolean(false);
4796         AtomicInteger numOfTdlsSessions = new AtomicInteger(0);
4797         Consumer<Integer> listener2 = new Consumer<Integer>() {
4798             @Override
4799             public void accept(Integer value) {
4800                 synchronized (mLock) {
4801                     numOfTdlsSessions.set(value);
4802                     mLock.notify();
4803                 }
4804             }
4805         };
4806 
4807         sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, true, mExecutor,
4808                 (enabledLocal) -> {
4809                     synchronized (mLock) {
4810                         enabled.set(enabledLocal);
4811                         mLock.notify();
4812                     }
4813                 });
4814         synchronized (mLock) {
4815             mLock.wait(TEST_WAIT_DURATION_MS);
4816         }
4817         assertTrue(enabled.get());
4818         sWifiManager.getNumberOfEnabledTdlsSessions(mExecutor, listener2);
4819         synchronized (mLock) {
4820             mLock.wait(TEST_WAIT_DURATION_MS);
4821         }
4822         assertEquals(1, numOfTdlsSessions.get());
4823 
4824         sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, false, mExecutor, (e) -> {});
4825         sWifiManager.getNumberOfEnabledTdlsSessions(mExecutor, listener2);
4826         synchronized (mLock) {
4827             mLock.wait(TEST_WAIT_DURATION_MS);
4828         }
4829         assertEquals(0, numOfTdlsSessions.get());
4830     }
4831 
4832     /**
4833      * Verify WifiNetworkSuggestion.Builder.setMacRandomizationSetting(WifiNetworkSuggestion
4834      * .RANDOMIZATION_NON_PERSISTENT) creates a
4835      * WifiConfiguration with macRandomizationSetting == RANDOMIZATION_NON_PERSISTENT.
4836      * Then verify by default, a WifiConfiguration created by suggestions should have
4837      * macRandomizationSetting == RANDOMIZATION_PERSISTENT.
4838      */
4839     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
4840     @Test
testSuggestionBuilderNonPersistentRandomization()4841     public void testSuggestionBuilderNonPersistentRandomization() throws Exception {
4842         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
4843                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE)
4844                 .setMacRandomizationSetting(WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT)
4845                 .build();
4846         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
4847                 sWifiManager.addNetworkSuggestions(Arrays.asList(suggestion)));
4848         verifySuggestionFoundWithMacRandomizationSetting(TEST_SSID,
4849                 WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT);
4850 
4851         suggestion = new WifiNetworkSuggestion.Builder()
4852                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE)
4853                 .build();
4854         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
4855                 sWifiManager.addNetworkSuggestions(Arrays.asList(suggestion)));
4856         verifySuggestionFoundWithMacRandomizationSetting(TEST_SSID,
4857                 WifiNetworkSuggestion.RANDOMIZATION_PERSISTENT);
4858     }
4859 
verifySuggestionFoundWithMacRandomizationSetting(String ssid, int macRandomizationSetting)4860     private void verifySuggestionFoundWithMacRandomizationSetting(String ssid,
4861             int macRandomizationSetting) {
4862         List<WifiNetworkSuggestion> retrievedSuggestions = sWifiManager.getNetworkSuggestions();
4863         for (WifiNetworkSuggestion entry : retrievedSuggestions) {
4864             if (entry.getSsid().equals(ssid)) {
4865                 assertEquals(macRandomizationSetting, entry.getMacRandomizationSetting());
4866                 return; // pass test after the MAC randomization setting is verified.
4867             }
4868         }
4869         fail("WifiNetworkSuggestion not found for SSID=" + ssid + ", macRandomizationSetting="
4870                 + macRandomizationSetting);
4871     }
4872 
4873     /**
4874      * Tests {@link WifiManager#getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(List)}
4875      */
4876     @Test
testGetAllWifiConfigForMatchedNetworkSuggestion()4877     public void testGetAllWifiConfigForMatchedNetworkSuggestion() {
4878         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4879         ScanResult scanResult = new ScanResult();
4880         scanResult.SSID = TEST_SSID;
4881         scanResult.capabilities = TEST_PSK_CAP;
4882         scanResult.BSSID = TEST_BSSID;
4883         List<ScanResult> testList = Arrays.asList(scanResult);
4884         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
4885                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build();
4886 
4887         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
4888                 sWifiManager.addNetworkSuggestions(Arrays.asList(suggestion)));
4889         List<WifiConfiguration> matchedResult;
4890         try {
4891             uiAutomation.adoptShellPermissionIdentity();
4892             matchedResult = sWifiManager
4893                     .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(testList);
4894         } finally {
4895             uiAutomation.dropShellPermissionIdentity();
4896         }
4897         // As suggestion is not approved, will return empty list.
4898         assertTrue(matchedResult.isEmpty());
4899     }
4900 
4901     /**
4902      * Tests {@link WifiManager#getMatchingScanResults(List, List)}
4903      */
4904     @Test
testGetMatchingScanResults()4905     public void testGetMatchingScanResults() {
4906         // Create pair of ScanResult and WifiNetworkSuggestion
4907         ScanResult scanResult = new ScanResult();
4908         scanResult.SSID = TEST_SSID;
4909         scanResult.capabilities = TEST_PSK_CAP;
4910         scanResult.BSSID = TEST_BSSID;
4911 
4912         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
4913                 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build();
4914 
4915         Map<WifiNetworkSuggestion, List<ScanResult>> matchedResults = sWifiManager
4916                 .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult));
4917         // Verify result is matched pair of ScanResult and WifiNetworkSuggestion
4918         assertEquals(scanResult.SSID, matchedResults.get(suggestion).get(0).SSID);
4919 
4920         // Change ScanResult to unmatched should return empty result.
4921         scanResult.SSID = TEST_SSID_UNQUOTED;
4922         matchedResults = sWifiManager
4923                 .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult));
4924         assertTrue(matchedResults.get(suggestion).isEmpty());
4925     }
4926 
4927     /**
4928      * Tests {@link WifiManager#disableEphemeralNetwork(String)}.
4929      */
4930     @Test
testDisableEphemeralNetwork()4931     public void testDisableEphemeralNetwork() throws Exception {
4932         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4933         List<WifiConfiguration> savedNetworks = null;
4934         try {
4935             uiAutomation.adoptShellPermissionIdentity();
4936             // Temporarily disable on all networks.
4937             savedNetworks = sWifiManager.getConfiguredNetworks();
4938             for (WifiConfiguration network : savedNetworks) {
4939                 sWifiManager.disableEphemeralNetwork(network.SSID);
4940             }
4941             // trigger a disconnect and wait for disconnect.
4942             sWifiManager.disconnect();
4943             waitForDisconnection();
4944 
4945             // Now trigger scan and ensure that the device does not connect to any networks.
4946             sWifiManager.startScan();
4947             ensureNotConnected();
4948         } finally {
4949             uiAutomation.dropShellPermissionIdentity();
4950             setWifiEnabled(false);
4951         }
4952     }
4953 
4954     /**
4955      * Tests {@link WifiManager#allowAutojoin(int, boolean)}.
4956      */
4957     @Test
testAllowAutojoin()4958     public void testAllowAutojoin() throws Exception {
4959         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
4960         List<WifiConfiguration> savedNetworks = null;
4961         try {
4962             uiAutomation.adoptShellPermissionIdentity();
4963             // disable autojoin on all networks.
4964             savedNetworks = sWifiManager.getConfiguredNetworks();
4965             for (WifiConfiguration network : savedNetworks) {
4966                 sWifiManager.allowAutojoin(network.networkId, false);
4967             }
4968             // trigger a disconnect and wait for disconnect.
4969             sWifiManager.disconnect();
4970             waitForDisconnection();
4971 
4972             // Now trigger scan and ensure that the device does not connect to any networks.
4973             sWifiManager.startScan();
4974             ensureNotConnected();
4975 
4976             // Now enable autojoin on all networks.
4977             for (WifiConfiguration network : savedNetworks) {
4978                 sWifiManager.allowAutojoin(network.networkId, true);
4979             }
4980 
4981             // Trigger a scan & wait for connection to one of the saved networks.
4982             sWifiManager.startScan();
4983             waitForConnection();
4984         } finally {
4985             // Restore auto join state.
4986             if (savedNetworks != null) {
4987                 for (WifiConfiguration network : savedNetworks) {
4988                     sWifiManager.allowAutojoin(network.networkId, network.allowAutojoin);
4989                 }
4990             }
4991             uiAutomation.dropShellPermissionIdentity();
4992         }
4993     }
4994 
4995     /**
4996      * Tests {@link WifiManager#allowAutojoinPasspoint(String, boolean)}.
4997      */
4998     @Test
testAllowAutojoinPasspoint()4999     public void testAllowAutojoinPasspoint() throws Exception {
5000         PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
5001         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5002         try {
5003             uiAutomation.adoptShellPermissionIdentity();
5004             sWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
5005             // Turn off auto-join
5006             sWifiManager.allowAutojoinPasspoint(
5007                     passpointConfiguration.getHomeSp().getFqdn(), false);
5008             // Turn on auto-join
5009             sWifiManager.allowAutojoinPasspoint(
5010                     passpointConfiguration.getHomeSp().getFqdn(), true);
5011         } finally {
5012             sWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn());
5013             uiAutomation.dropShellPermissionIdentity();
5014         }
5015     }
5016 
5017     /**
5018      * Tests {@link WifiManager#allowAutojoinGlobal(boolean)}.
5019      */
5020     @Test
testAllowAutojoinGlobal()5021     public void testAllowAutojoinGlobal() throws Exception {
5022         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5023         try {
5024             uiAutomation.adoptShellPermissionIdentity();
5025             // disable autojoin on all networks.
5026             sWifiManager.allowAutojoinGlobal(false);
5027 
5028             // trigger a disconnect and wait for disconnect.
5029             sWifiManager.disconnect();
5030             waitForDisconnection();
5031 
5032             // Now trigger scan and ensure that the device does not connect to any networks.
5033             sWifiManager.startScan();
5034             ensureNotConnected();
5035 
5036             // verify null is returned when attempting to get current configured network.
5037             WifiConfiguration config = sWifiManager.getPrivilegedConnectedNetwork();
5038             assertNull("config should be null because wifi is not connected", config);
5039 
5040             // Now enable autojoin on all networks.
5041             sWifiManager.allowAutojoinGlobal(true);
5042 
5043             // Trigger a scan & wait for connection to one of the saved networks.
5044             sWifiManager.startScan();
5045             waitForConnection();
5046         } finally {
5047             // Re-enable auto join if the test fails for some reason.
5048             sWifiManager.allowAutojoinGlobal(true);
5049             uiAutomation.dropShellPermissionIdentity();
5050         }
5051     }
5052 
5053     /**
5054      * Verify the invalid and valid usages of {@code WifiManager#queryAutojoinGlobal}.
5055      */
5056     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
5057     @Test
testQueryAutojoinGlobal()5058     public void testQueryAutojoinGlobal() throws Exception {
5059         AtomicBoolean enabled = new AtomicBoolean(false);
5060         Consumer<Boolean> listener = new Consumer<Boolean>() {
5061             @Override
5062             public void accept(Boolean value) {
5063                 synchronized (mLock) {
5064                     enabled.set(value);
5065                     mLock.notify();
5066                 }
5067             }
5068         };
5069         // Test invalid inputs trigger IllegalArgumentException
5070         assertThrows("null executor should trigger exception", NullPointerException.class,
5071                 () -> sWifiManager.queryAutojoinGlobal(null, listener));
5072         assertThrows("null listener should trigger exception", NullPointerException.class,
5073                 () -> sWifiManager.queryAutojoinGlobal(mExecutor, null));
5074 
5075         // Test caller with no permission triggers SecurityException.
5076         assertThrows("No permission should trigger SecurityException", SecurityException.class,
5077                 () -> sWifiManager.queryAutojoinGlobal(mExecutor, listener));
5078 
5079         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5080         try {
5081             uiAutomation.adoptShellPermissionIdentity();
5082             // Test get/set autojoin global enabled
5083             sWifiManager.allowAutojoinGlobal(true);
5084             sWifiManager.queryAutojoinGlobal(mExecutor, listener);
5085             synchronized (mLock) {
5086                 mLock.wait(TEST_WAIT_DURATION_MS);
5087             }
5088             assertTrue(enabled.get());
5089 
5090             // Test get/set autojoin global disabled
5091             sWifiManager.allowAutojoinGlobal(false);
5092             sWifiManager.queryAutojoinGlobal(mExecutor, listener);
5093             synchronized (mLock) {
5094                 mLock.wait(TEST_WAIT_DURATION_MS);
5095             }
5096             assertFalse(enabled.get());
5097         } finally {
5098             // Re-enable auto join if the test fails for some reason.
5099             sWifiManager.allowAutojoinGlobal(true);
5100             uiAutomation.dropShellPermissionIdentity();
5101         }
5102     }
5103 
5104     /**
5105      * Tests {@link WifiManager#setPerSsidRoamingMode(WifiSsid, int)},
5106      * {@link WifiManager#getPerSsidRoamingModes(Executor, Consumer)},
5107      * and {@link WifiManager#removePerSsidRoamingMode(WifiSsid)}.
5108      */
5109     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
5110     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM,
5111             codeName = "VanillaIceCream")
5112     @Test
testPerSsidRoamingMode()5113     public void testPerSsidRoamingMode() throws Exception {
5114         if (!sWifiManager.isAggressiveRoamingModeSupported()) {
5115             // skip the test if aggressive roaming mode is not supported
5116             return;
5117         }
5118         WifiSsid testSsid = WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8));
5119         Map<String, Integer> roamingModes = new HashMap<>();
5120         Consumer<Map<String, Integer>> listener = new Consumer<Map<String, Integer>>() {
5121             @Override
5122             public void accept(Map<String, Integer> value) {
5123                 synchronized (mLock) {
5124                     roamingModes.clear();
5125                     roamingModes.putAll(value);
5126                     mLock.notify();
5127                 }
5128             }
5129         };
5130 
5131         // Test caller with no permission triggers SecurityException.
5132         assertThrows("No permission should trigger SecurityException", SecurityException.class,
5133                 () -> sWifiManager.setPerSsidRoamingMode(testSsid,
5134                         WifiManager.ROAMING_MODE_AGGRESSIVE));
5135         assertThrows("No permission should trigger SecurityException", SecurityException.class,
5136                 () -> sWifiManager.removePerSsidRoamingMode(testSsid));
5137         assertThrows("No permission should trigger SecurityException", SecurityException.class,
5138                 () -> sWifiManager.getPerSsidRoamingModes(mExecutor, listener));
5139 
5140         // Test that invalid inputs trigger an Exception.
5141         assertThrows("null WifiSsid should trigger exception", NullPointerException.class,
5142                 () -> sWifiManager.setPerSsidRoamingMode(null,
5143                         WifiManager.ROAMING_MODE_AGGRESSIVE));
5144         assertThrows("null WifiSsid should trigger exception", NullPointerException.class,
5145                 () -> sWifiManager.removePerSsidRoamingMode(null));
5146         assertThrows("null executor should trigger exception", NullPointerException.class,
5147                 () -> sWifiManager.getPerSsidRoamingModes(null, listener));
5148         assertThrows("null listener should trigger exception", NullPointerException.class,
5149                 () -> sWifiManager.getPerSsidRoamingModes(mExecutor, null));
5150 
5151         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5152         try {
5153             uiAutomation.adoptShellPermissionIdentity();
5154             sWifiManager.setPerSsidRoamingMode(testSsid, WifiManager.ROAMING_MODE_AGGRESSIVE);
5155             sWifiManager.getPerSsidRoamingModes(mExecutor, listener);
5156             Thread.sleep(TEST_WAIT_DURATION_MS);
5157             assertTrue(
5158                     roamingModes.get(testSsid.toString()) == WifiManager.ROAMING_MODE_AGGRESSIVE);
5159             sWifiManager.removePerSsidRoamingMode(testSsid);
5160             sWifiManager.getPerSsidRoamingModes(mExecutor, listener);
5161             Thread.sleep(TEST_WAIT_DURATION_MS);
5162             assertNull(roamingModes.get(testSsid.toString()));
5163         } finally {
5164             uiAutomation.dropShellPermissionIdentity();
5165         }
5166     }
5167 
5168     /**
5169      * Verify the invalid and valid usages of {@code WifiManager#setPnoScanState}.
5170      */
5171     @Test
5172     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
testSetPnoScanState()5173     public void testSetPnoScanState() throws Exception {
5174         // Test caller with no permission triggers SecurityException.
5175         assertThrows("No permission should trigger SecurityException", SecurityException.class,
5176                 () -> sWifiManager.setPnoScanState(WifiManager.PNO_SCAN_STATE_ENABLED));
5177 
5178         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5179         try {
5180             uiAutomation.adoptShellPermissionIdentity();
5181             sWifiManager.setPnoScanState(WifiManager.PNO_SCAN_STATE_ENABLED);
5182         } finally {
5183             uiAutomation.dropShellPermissionIdentity();
5184         }
5185     }
5186 
5187     /**
5188      * Tests {@link WifiManager#isWapiSupported()} does not crash.
5189      */
5190     @Test
testIsWapiSupported()5191     public void testIsWapiSupported() throws Exception {
5192         sWifiManager.isWapiSupported();
5193     }
5194 
5195     /**
5196      * Tests {@link WifiManager#isWpa3SaePublicKeySupported()} does not crash.
5197      */
5198     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5199     @Test
testIsWpa3SaePublicKeySupported()5200     public void testIsWpa3SaePublicKeySupported() throws Exception {
5201         sWifiManager.isWpa3SaePublicKeySupported();
5202     }
5203 
5204     /**
5205      * Tests {@link WifiManager#isWpa3SaeH2eSupported()} does not crash.
5206      */
5207     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5208     @Test
testIsWpa3SaeH2eSupported()5209     public void testIsWpa3SaeH2eSupported() throws Exception {
5210         sWifiManager.isWpa3SaeH2eSupported();
5211     }
5212 
5213     /**
5214      * Tests {@link WifiManager#isWifiDisplayR2Supported()} does not crash.
5215      */
5216     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5217     @Test
testIsWifiDisplayR2Supported()5218     public void testIsWifiDisplayR2Supported() throws Exception {
5219         sWifiManager.isWifiDisplayR2Supported();
5220     }
5221 
5222     /**
5223      * Tests {@link WifiManager#isP2pSupported()} returns true
5224      * if this device supports it, otherwise, ensure no crash.
5225      */
5226     @Test
testIsP2pSupported()5227     public void testIsP2pSupported() throws Exception {
5228         if (WifiFeature.isP2pSupported(sContext)) {
5229             // if this device supports P2P, ensure hw capability is correct.
5230             assertTrue(sWifiManager.isP2pSupported());
5231         } else {
5232             // ensure no crash.
5233             sWifiManager.isP2pSupported();
5234         }
5235 
5236     }
5237 
5238     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5239     @Test
testIsMultiStaConcurrencySupported()5240     public void testIsMultiStaConcurrencySupported() throws Exception {
5241         // ensure no crash.
5242         sWifiManager.isStaApConcurrencySupported();
5243     }
5244 
getTargetPasspointConfiguration( List<PasspointConfiguration> configurationList, String uniqueId)5245     private PasspointConfiguration getTargetPasspointConfiguration(
5246             List<PasspointConfiguration> configurationList, String uniqueId) {
5247         if (configurationList == null || configurationList.isEmpty()) {
5248             return null;
5249         }
5250         for (PasspointConfiguration config : configurationList) {
5251             if (TextUtils.equals(config.getUniqueId(), uniqueId)) {
5252                 return config;
5253             }
5254         }
5255         return null;
5256     }
5257 
5258     /**
5259      * Test that {@link WifiManager#is60GHzBandSupported()} throws UnsupportedOperationException
5260      * if the release is older than S.
5261      */
5262     @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.R)
5263     @Test
testIs60GhzBandSupportedOnROrOlder()5264     public void testIs60GhzBandSupportedOnROrOlder() throws Exception {
5265         // check for 60ghz support with wifi enabled
5266         try {
5267             sWifiManager.is60GHzBandSupported();
5268             fail("Expected UnsupportedOperationException");
5269         } catch (UnsupportedOperationException ex) {
5270         }
5271     }
5272 
5273     /**
5274      * Test that {@link WifiManager#is60GHzBandSupported()} returns successfully in
5275      * both Wifi enabled/disabled states for release newer than R.
5276      * Note that the response depends on device support and hence both true/false
5277      * are valid responses.
5278      */
5279     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5280     @Test
testIs60GhzBandSupportedOnSOrNewer()5281     public void testIs60GhzBandSupportedOnSOrNewer() throws Exception {
5282         // check for 60ghz support with wifi enabled
5283         boolean isSupportedWhenWifiEnabled = sWifiManager.is60GHzBandSupported();
5284 
5285         // Check for 60GHz support with wifi disabled
5286         setWifiEnabled(false);
5287         PollingCheck.check(
5288                 "Wifi not disabled!",
5289                 20000,
5290                 () -> !sWifiManager.isWifiEnabled());
5291         boolean isSupportedWhenWifiDisabled = sWifiManager.is60GHzBandSupported();
5292 
5293         // If Support is true when WiFi is disable, then it has to be true when it is enabled.
5294         // Note, the reverse is a valid case.
5295         if (isSupportedWhenWifiDisabled) {
5296             assertTrue(isSupportedWhenWifiEnabled);
5297         }
5298     }
5299 
5300     /**
5301      * Tests {@link WifiManager#isTrustOnFirstUseSupported()} does not crash.
5302      */
5303     // TODO(b/196180536): Wait for T SDK finalization before changing
5304     // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)`
5305     @SdkSuppress(minSdkVersion = 31)
5306     @Test
testIsTrustOnFirstUseSupported()5307     public void testIsTrustOnFirstUseSupported() throws Exception {
5308         sWifiManager.isTrustOnFirstUseSupported();
5309     }
5310 
5311     public class TestCoexCallback extends WifiManager.CoexCallback {
5312         private Object mCoexLock;
5313         private int mOnCoexUnsafeChannelChangedCount;
5314         private List<CoexUnsafeChannel> mCoexUnsafeChannels;
5315         private int mCoexRestrictions;
5316 
TestCoexCallback(Object lock)5317         TestCoexCallback(Object lock) {
5318             mCoexLock = lock;
5319         }
5320 
5321         @Override
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, int restrictions)5322         public void onCoexUnsafeChannelsChanged(
5323                     @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) {
5324             synchronized (mCoexLock) {
5325                 mCoexUnsafeChannels = unsafeChannels;
5326                 mCoexRestrictions = restrictions;
5327                 mOnCoexUnsafeChannelChangedCount++;
5328                 mCoexLock.notify();
5329             }
5330         }
5331 
getOnCoexUnsafeChannelChangedCount()5332         public int getOnCoexUnsafeChannelChangedCount() {
5333             synchronized (mCoexLock) {
5334                 return mOnCoexUnsafeChannelChangedCount;
5335             }
5336         }
5337 
getCoexUnsafeChannels()5338         public List<CoexUnsafeChannel> getCoexUnsafeChannels() {
5339             return mCoexUnsafeChannels;
5340         }
5341 
getCoexRestrictions()5342         public int getCoexRestrictions() {
5343             return mCoexRestrictions;
5344         }
5345     }
5346 
5347     /**
5348      * Test that coex-related methods fail without the needed privileged permissions
5349      */
5350     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5351     @Test
testCoexMethodsShouldFailNoPermission()5352     public void testCoexMethodsShouldFailNoPermission() {
5353         try {
5354             sWifiManager.setCoexUnsafeChannels(Collections.emptyList(), 0);
5355             fail("setCoexUnsafeChannels should not succeed - privileged call");
5356         } catch (SecurityException e) {
5357             // expected
5358         }
5359         final TestCoexCallback callback = new TestCoexCallback(mLock);
5360         try {
5361             sWifiManager.registerCoexCallback(mExecutor, callback);
5362             fail("registerCoexCallback should not succeed - privileged call");
5363         } catch (SecurityException e) {
5364             // expected
5365         }
5366         try {
5367             sWifiManager.unregisterCoexCallback(callback);
5368             fail("unregisterCoexCallback should not succeed - privileged call");
5369         } catch (SecurityException e) {
5370             // expected
5371         }
5372     }
5373 
5374     /**
5375      * Test that coex-related methods succeed in setting the current unsafe channels and notifying
5376      * the listener. Since the default coex algorithm may be enabled, no-op is also valid behavior.
5377      */
5378     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5379     @Test
testListenOnCoexUnsafeChannels()5380     public void testListenOnCoexUnsafeChannels() {
5381         // These below API's only work with privileged permissions (obtained via shell identity
5382         // for test)
5383         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5384         List<CoexUnsafeChannel> prevUnsafeChannels = new ArrayList<>();
5385         int prevRestrictions = -1;
5386         try {
5387             uiAutomation.adoptShellPermissionIdentity();
5388             synchronized (mLock) {
5389                 try {
5390                     boolean defaultAlgoEnabled = false;
5391                     final TestCoexCallback callback = new TestCoexCallback(mLock);
5392                     sWifiManager.registerCoexCallback(mExecutor, callback);
5393 
5394                     // Callback should be called after registering
5395                     mLock.wait(TEST_WAIT_DURATION_MS);
5396                     assertEquals(1, callback.getOnCoexUnsafeChannelChangedCount());
5397 
5398                     // Store the previous coex channels and try setting new coex channels 5 times.
5399                     //
5400                     // If the default algorithm is disabled, we'll get exactly 5 callbacks, and we
5401                     // can verify that the update channels match what we inputted.
5402                     //
5403                     // If the default algorithm is enabled, then the callbacks will trigger
5404                     // according to the algorithm, which may or may not trigger during the test.
5405                     // Thus we try 5 times and see if the callbacks match the number of tries, since
5406                     // it's highly unlikely that the default algorithm will update the channels
5407                     // exactly 5 times during the test.
5408                     prevUnsafeChannels = callback.getCoexUnsafeChannels();
5409                     prevRestrictions = callback.getCoexRestrictions();
5410                     List<CoexUnsafeChannel> testChannels = null;
5411                     final int testRestrictions = COEX_RESTRICTION_WIFI_DIRECT
5412                             | COEX_RESTRICTION_SOFTAP | COEX_RESTRICTION_WIFI_AWARE;
5413                     for (int i = 0; i < 5; i++) {
5414                         testChannels = List.of(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 1 + i));
5415                         sWifiManager.setCoexUnsafeChannels(testChannels, testRestrictions);
5416                         mLock.wait(TEST_WAIT_DURATION_MS);
5417                         if (callback.getOnCoexUnsafeChannelChangedCount() != i + 2) {
5418                             defaultAlgoEnabled = true;
5419                             break;
5420                         }
5421                     }
5422 
5423                     if (!defaultAlgoEnabled) {
5424                         int currentCallbackCount = callback.getOnCoexUnsafeChannelChangedCount();
5425                         assertEquals(testChannels, callback.getCoexUnsafeChannels());
5426                         assertEquals(testRestrictions, callback.getCoexRestrictions());
5427                         // Unregister callback and try setting again
5428                         sWifiManager.unregisterCoexCallback(callback);
5429                         sWifiManager.setCoexUnsafeChannels(
5430                                 List.of(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 11)),
5431                                 testRestrictions);
5432                         mLock.wait(TEST_WAIT_DURATION_MS);
5433                         // Callback should not be called here since it was unregistered.
5434                         assertThat(callback.getOnCoexUnsafeChannelChangedCount())
5435                                 .isEqualTo(currentCallbackCount);
5436                     }
5437                 } catch (InterruptedException e) {
5438                     fail("Thread interrupted unexpectedly while waiting on mLock");
5439                 }
5440             }
5441         } finally {
5442             // Reset the previous unsafe channels if we overrode them.
5443             if (prevRestrictions != -1) {
5444                 sWifiManager.setCoexUnsafeChannels(prevUnsafeChannels, prevRestrictions);
5445             }
5446             uiAutomation.dropShellPermissionIdentity();
5447         }
5448     }
5449 
5450     /**
5451      * Verify that secure WPA-Enterprise network configurations can be added and updated.
5452      */
5453     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5454     @Test
testSecureEnterpriseConfigurationsAccepted()5455     public void testSecureEnterpriseConfigurationsAccepted() throws Exception {
5456         WifiConfiguration wifiConfiguration = new WifiConfiguration();
5457         wifiConfiguration.SSID = SSID1;
5458         wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
5459         wifiConfiguration.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
5460         int networkId = INVALID_NETWORK_ID;
5461 
5462         // These below API's only work with privileged permissions (obtained via shell identity
5463         // for test)
5464         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5465         try {
5466             uiAutomation.adoptShellPermissionIdentity();
5467 
5468             // Now configure it correctly with a Root CA cert and domain name
5469             wifiConfiguration.enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
5470             wifiConfiguration.enterpriseConfig.setAltSubjectMatch(TEST_DOM_SUBJECT_MATCH);
5471 
5472             // Verify that the network is added
5473             networkId = sWifiManager.addNetwork(wifiConfiguration);
5474             assertNotEquals(INVALID_NETWORK_ID, networkId);
5475 
5476             // Verify that the update API accepts configurations configured securely
5477             wifiConfiguration.networkId = networkId;
5478             assertEquals(networkId, sWifiManager.updateNetwork(wifiConfiguration));
5479         } finally {
5480             if (networkId != INVALID_NETWORK_ID) {
5481                 // Clean up the previously added network
5482                 sWifiManager.removeNetwork(networkId);
5483             }
5484             uiAutomation.dropShellPermissionIdentity();
5485         }
5486     }
5487 
5488     /**
5489      * Tests {@link WifiManager#isPasspointTermsAndConditionsSupported)} does not crash.
5490      */
5491     @Test
testIsPasspointTermsAndConditionsSupported()5492     public void testIsPasspointTermsAndConditionsSupported() throws Exception {
5493         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
5494             // Skip the test if wifi module version is older than S.
5495             return;
5496         }
5497         sWifiManager.isPasspointTermsAndConditionsSupported();
5498     }
5499 
5500     /**
5501      * Test that call to {@link WifiManager#setOverrideCountryCode()},
5502      * {@link WifiManager#clearOverrideCountryCode()} and
5503      * {@link WifiManager#setDefaultCountryCode()} need privileged permission
5504      * and the permission is not even given to shell user.
5505      */
5506     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5507     @Test
testManageCountryCodeMethodsFailWithoutPermissions()5508     public void testManageCountryCodeMethodsFailWithoutPermissions() throws Exception {
5509         ShellIdentityUtils.invokeWithShellPermissions(() -> {
5510             try {
5511                 sWifiManager.setOverrideCountryCode(TEST_COUNTRY_CODE);
5512                 fail("setOverrideCountryCode() expected to fail - privileged call");
5513             } catch (SecurityException e) {
5514                 // expected
5515             }
5516 
5517             try {
5518                 sWifiManager.clearOverrideCountryCode();
5519                 fail("clearOverrideCountryCode() expected to fail - privileged call");
5520             } catch (SecurityException e) {
5521                 // expected
5522             }
5523 
5524             try {
5525                 sWifiManager.setDefaultCountryCode(TEST_COUNTRY_CODE);
5526                 fail("setDefaultCountryCode() expected to fail - privileged call");
5527             } catch (SecurityException e) {
5528                 // expected
5529             }
5530         });
5531     }
5532 
5533     /**
5534      * Tests {@link WifiManager#flushPasspointAnqpCache)} does not crash.
5535      */
5536     @Test
testFlushPasspointAnqpCache()5537     public void testFlushPasspointAnqpCache() throws Exception {
5538         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
5539             // Skip the test if wifi module version is older than S.
5540             return;
5541         }
5542         // The below API only works with privileged permissions (obtained via shell identity
5543         // for test)
5544         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5545         try {
5546             uiAutomation.adoptShellPermissionIdentity();
5547             sWifiManager.flushPasspointAnqpCache();
5548         } finally {
5549             uiAutomation.dropShellPermissionIdentity();
5550         }
5551     }
5552 
5553     /**
5554      * Tests {@link WifiManager#setWifiPasspointEnabled)} raise security exception without
5555      * permission.
5556      */
5557     // TODO(b/139192273): Wait for T SDK finalization before changing
5558     // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.T)`
5559     @SdkSuppress(minSdkVersion = 31)
5560     @Test
testEnablePasspointWithoutPermission()5561     public void testEnablePasspointWithoutPermission() throws Exception {
5562         try {
5563             sWifiManager.setWifiPasspointEnabled(true);
5564             fail("setWifiPasspointEnabled() expected to fail - privileged call");
5565         } catch (SecurityException e) {
5566             // expected
5567         }
5568     }
5569 
5570     /**
5571      * Tests {@link WifiManager#setWifiPasspointEnabled)} does not crash and returns success.
5572      */
5573     // TODO(b/139192273): Wait for T SDK finalization before changing
5574     // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.T)`
5575     @SdkSuppress(minSdkVersion = 31)
5576     @Test
testEnablePasspoint()5577     public void testEnablePasspoint() throws Exception {
5578         // The below API only works with privileged permissions (obtained via shell identity
5579         // for test)
5580         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5581         try {
5582             uiAutomation.adoptShellPermissionIdentity();
5583             // Check if passpoint is enabled by default.
5584             assertTrue(sWifiManager.isWifiPasspointEnabled());
5585             // Try to disable passpoint
5586             sWifiManager.setWifiPasspointEnabled(false);
5587             PollingCheck.check("Wifi passpoint turn off failed!", 2_000,
5588                     () -> !sWifiManager.isWifiPasspointEnabled());
5589             // Try to enable passpoint
5590             sWifiManager.setWifiPasspointEnabled(true);
5591             PollingCheck.check("Wifi passpoint turn on failed!", 2_000,
5592                     () -> sWifiManager.isWifiPasspointEnabled());
5593         } finally {
5594             uiAutomation.dropShellPermissionIdentity();
5595         }
5596     }
5597 
5598     /**
5599      * Tests {@link WifiManager#isDecoratedIdentitySupported)} does not crash.
5600      */
5601     @Test
testIsDecoratedIdentitySupported()5602     public void testIsDecoratedIdentitySupported() throws Exception {
5603         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
5604             // Skip the test if wifi module version is older than S.
5605             return;
5606         }
5607         sWifiManager.isDecoratedIdentitySupported();
5608     }
5609 
5610     /**
5611      * Tests {@link WifiManager#setCarrierNetworkOffloadEnabled)} and
5612      * {@link WifiManager#isCarrierNetworkOffloadEnabled} work as expected.
5613      */
5614     @Test
testSetCarrierNetworkOffloadEnabled()5615     public void testSetCarrierNetworkOffloadEnabled() {
5616         if (!WifiFeature.isWifiSupported(sContext)
5617                 || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
5618             // skip the test if WiFi is not supported
5619             return;
5620         }
5621         assertTrue(sWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
5622         // The below API only works with privileged permissions (obtained via shell identity
5623         // for test)
5624         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5625         try {
5626             uiAutomation.adoptShellPermissionIdentity();
5627             sWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, false, false);
5628             assertFalse(sWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
5629         } finally {
5630             sWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, false, true);
5631             uiAutomation.dropShellPermissionIdentity();
5632         }
5633         assertTrue(sWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
5634     }
5635 
5636     /**
5637      * Test that {@link WifiManager#getUsableChannels(int, int)},
5638      * {@link WifiManager#getAllowedChannels(int, int)}
5639      * throws UnsupportedOperationException if the release is older than S.
5640      */
5641     @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.R)
5642     @Test
testGetAllowedUsableChannelsOnROrOlder()5643     public void testGetAllowedUsableChannelsOnROrOlder() throws Exception {
5644         try {
5645             sWifiManager.getAllowedChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5646             fail("getAllowedChannels Expected to fail - UnsupportedOperationException");
5647         } catch (UnsupportedOperationException ex) {}
5648 
5649         try {
5650             sWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5651             fail("getUsableChannels Expected to fail - UnsupportedOperationException");
5652         } catch (UnsupportedOperationException ex) {}
5653     }
5654 
5655     /**
5656      * Tests {@link WifiManager#getAllowedChannels(int, int))} does not crash
5657      */
5658     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5659     @Test
testGetAllowedChannels()5660     public void testGetAllowedChannels() throws Exception {
5661         // The below API only works with privileged permissions (obtained via shell identity
5662         // for test)
5663         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5664         try {
5665             WifiAvailableChannel channel = new WifiAvailableChannel(2412, OP_MODE_SAP);
5666             assertEquals(channel.getFrequencyMhz(), 2412);
5667             assertEquals(channel.getOperationalModes(), OP_MODE_SAP);
5668             final List<Integer> valid24GhzFreqs = Arrays.asList(
5669                 2412, 2417, 2422, 2427, 2432, 2437, 2442,
5670                 2447, 2452, 2457, 2462, 2467, 2472, 2484);
5671             Set<Integer> supported24GhzFreqs = new HashSet<Integer>();
5672             uiAutomation.adoptShellPermissionIdentity();
5673             List<WifiAvailableChannel> allowedChannels =
5674                     sWifiManager.getAllowedChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5675             assertNotNull(allowedChannels);
5676             for (WifiAvailableChannel ch : allowedChannels) {
5677                 //Must contain a valid 2.4GHz frequency
5678                 assertTrue(valid24GhzFreqs.contains(ch.getFrequencyMhz()));
5679                 if(ch.getFrequencyMhz() <= 2462) {
5680                     //Channels 1-11 are supported for STA in all countries
5681                     assertEquals(ch.getOperationalModes() & OP_MODE_STA, OP_MODE_STA);
5682                     supported24GhzFreqs.add(ch.getFrequencyMhz());
5683                 }
5684             }
5685             //Channels 1-11 are supported for STA in all countries
5686             assertEquals(supported24GhzFreqs.size(), 11);
5687         } catch (UnsupportedOperationException ex) {
5688             //expected if the device does not support this API
5689         } catch (Exception ex) {
5690             fail("getAllowedChannels unexpected Exception " + ex);
5691         } finally {
5692             uiAutomation.dropShellPermissionIdentity();
5693         }
5694     }
5695 
5696     /**
5697      * Tests {@link WifiAvailableChannel#getChannelWidth()}.
5698      */
5699     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5700     @RequiresFlagsEnabled(Flags.FLAG_GET_CHANNEL_WIDTH_API)
5701     @ApiTest(apis = {"android.net.wifi.WifiAvailableChannel#getChannelWidth"})
5702     @Test
testGetAllowedChannelsWidth()5703     public void testGetAllowedChannelsWidth() throws Exception {
5704         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5705         try {
5706             final List<Integer> valid24GhzFreqs = Arrays.asList(2412, 2417, 2422, 2427, 2432, 2437,
5707                     2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484);
5708             uiAutomation.adoptShellPermissionIdentity();
5709             List<WifiAvailableChannel> allowedChannels = sWifiManager.getAllowedChannels(
5710                     WIFI_BAND_24_GHZ, OP_MODE_STA);
5711             assertNotNull(allowedChannels);
5712             for (WifiAvailableChannel ch : allowedChannels) {
5713                 //Must contain a valid 2.4GHz frequency
5714                 assertTrue(valid24GhzFreqs.contains(ch.getFrequencyMhz()));
5715                 if (ch.getFrequencyMhz() <= 2462) {
5716                     //Channels 1-11 are supported for STA in all countries
5717                     assertEquals(ch.getOperationalModes() & OP_MODE_STA, OP_MODE_STA);
5718                     assertEquals(ch.getChannelWidth(), ScanResult.CHANNEL_WIDTH_20MHZ);
5719                 }
5720             }
5721         } catch (UnsupportedOperationException ex) {
5722             //expected if the device does not support this API
5723         } catch (Exception ex) {
5724             fail("getAllowedChannels unexpected Exception " + ex);
5725         } finally {
5726             uiAutomation.dropShellPermissionIdentity();
5727         }
5728     }
5729 
5730     /**
5731      * Tests {@link WifiManager#getUsableChannels(int, int))} does not crash
5732      * and returns at least one 2G channel in STA and WFD GO modes (if WFD is supported)
5733      */
5734     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
5735     @Test
testGetUsableChannelsStaWfdMode()5736     public void testGetUsableChannelsStaWfdMode() throws Exception {
5737         // The below API only works with privileged permissions (obtained via shell identity
5738         // for test)
5739         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5740         try {
5741             uiAutomation.adoptShellPermissionIdentity();
5742             List<WifiAvailableChannel> usableStaChannels =
5743                     sWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_STA);
5744             //There must be at least one usable STA channel in 2.4GHz band
5745             assertFalse(usableStaChannels.isEmpty());
5746             if (sWifiManager.isP2pSupported()) {
5747                 List<WifiAvailableChannel> usableGoChannels =
5748                         sWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_WIFI_DIRECT_GO);
5749                 //There must be at least one usable P2P channel in 2.4GHz band
5750                 assertFalse(usableGoChannels.isEmpty());
5751             }
5752 
5753         } catch (UnsupportedOperationException ex) {
5754             //expected if the device does not support this API
5755         } catch (Exception ex) {
5756             fail("getUsableChannels unexpected Exception " + ex);
5757         } finally {
5758             uiAutomation.dropShellPermissionIdentity();
5759         }
5760     }
5761 
5762     /**
5763      * Tests {@link WifiManager#getChannelData(Executor, Consumer<List<Bundle>>)}
5764      * does not crash.
5765      */
5766     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
5767     @Test
testGetChannelData()5768     public void testGetChannelData() throws Exception {
5769         List<Bundle> dataList = new ArrayList<>();
5770         Consumer<List<Bundle>> listener = new Consumer<List<Bundle>>() {
5771             @Override
5772             public void accept(List<Bundle> value) {
5773                 synchronized (mLock) {
5774                     dataList.addAll(value);
5775                     mLock.notify();
5776                 }
5777             }
5778         };
5779         // Test invalid inputs trigger IllegalArgumentException
5780         assertThrows("null executor should trigger exception", NullPointerException.class,
5781                 () -> sWifiManager.getChannelData(null, listener));
5782         assertThrows("null listener should trigger exception", NullPointerException.class,
5783                 () -> sWifiManager.getChannelData(mExecutor, null));
5784 
5785         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5786         try {
5787             uiAutomation.adoptShellPermissionIdentity();
5788             // Start scan and wait for scan results
5789             startScan();
5790             sWifiManager.getChannelData(mExecutor, listener);
5791             synchronized (mLock) {
5792                 mLock.wait(TEST_WAIT_DURATION_MS);
5793             }
5794             if (sWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) {
5795                 assertFalse(dataList.isEmpty());
5796             }
5797         } catch (UnsupportedOperationException ex) {
5798             //expected if the device does not support this API
5799         } catch (Exception ex) {
5800             fail("getChannelData unexpected Exception " + ex);
5801         } finally {
5802             uiAutomation.dropShellPermissionIdentity();
5803         }
5804     }
5805 
5806     /**
5807      * Validate that the Passpoint feature is enabled on the device.
5808      */
5809     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
5810     @Test
testPasspointCapability()5811     public void testPasspointCapability() {
5812         if (PropertyUtil.getVsrApiLevel() < Build.VERSION_CODES.S) {
5813             return;
5814         }
5815         PackageManager packageManager = sContext.getPackageManager();
5816         assertTrue("Passpoint must be supported",
5817                 packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT));
5818     }
5819 
5820     /**
5821      * Validate add and remove SuggestionUserApprovalStatusListener. And verify the listener's
5822      * stickiness.
5823      */
5824     @Test
testAddRemoveSuggestionUserApprovalStatusListener()5825     public void testAddRemoveSuggestionUserApprovalStatusListener() throws Exception {
5826         if (!WifiFeature.isWifiSupported(sContext)
5827                 || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
5828             return;
5829         }
5830         CountDownLatch countDownLatch = new CountDownLatch(1);
5831         TestUserApprovalStatusListener listener = new TestUserApprovalStatusListener(
5832                 countDownLatch);
5833         try {
5834             sWifiManager.addSuggestionUserApprovalStatusListener(mExecutor, listener);
5835             assertTrue(countDownLatch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS));
5836         } finally {
5837             sWifiManager.removeSuggestionUserApprovalStatusListener(listener);
5838         }
5839     }
5840 
5841     private static class TestUserApprovalStatusListener implements
5842             WifiManager.SuggestionUserApprovalStatusListener {
5843         private final CountDownLatch mBlocker;
5844 
TestUserApprovalStatusListener(CountDownLatch countDownLatch)5845         public TestUserApprovalStatusListener(CountDownLatch countDownLatch) {
5846             mBlocker = countDownLatch;
5847         }
5848         @Override
onUserApprovalStatusChange(int status)5849         public void onUserApprovalStatusChange(int status) {
5850             mBlocker.countDown();
5851         }
5852     }
5853 
5854     /**
5855      * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} raise security exception
5856      * without permission.
5857      */
5858     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
5859     @Test
testIsStaConcurrencyForMultiInternetSupported()5860     public void testIsStaConcurrencyForMultiInternetSupported() throws Exception {
5861         // ensure no crash.
5862         sWifiManager.isStaConcurrencyForMultiInternetSupported();
5863     }
5864 
5865     /**
5866      * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} raise security exception
5867      * without permission.
5868      */
5869     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
5870     @Test
testSetStaConcurrencyForMultiInternetModeWithoutPermission()5871     public void testSetStaConcurrencyForMultiInternetModeWithoutPermission() throws Exception {
5872         if (!WifiFeature.isWifiSupported(sContext)
5873                 || !sWifiManager.isStaConcurrencyForMultiInternetSupported()) {
5874             // skip the test if WiFi is not supported or multi internet feature not supported.
5875             return;
5876         }
5877         try {
5878             sWifiManager.setStaConcurrencyForMultiInternetMode(
5879                     WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED);
5880             fail("setWifiPasspointEnabled() expected to fail - privileged call");
5881         } catch (SecurityException e) {
5882             // expected
5883         }
5884     }
5885 
5886     /**
5887      * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} does not crash.
5888      */
5889     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
5890     @Test
testSetStaConcurrencyForMultiInternetMode()5891     public void testSetStaConcurrencyForMultiInternetMode() throws Exception {
5892         if (!WifiFeature.isWifiSupported(sContext)
5893                 || !sWifiManager.isStaConcurrencyForMultiInternetSupported()) {
5894             // skip the test if WiFi is not supported or multi internet feature not supported.
5895             return;
5896         }
5897 
5898         // The below API only works with privileged permissions (obtained via shell identity
5899         // for test)
5900         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
5901         try {
5902             uiAutomation.adoptShellPermissionIdentity();
5903             // Try to disable multi internet
5904             sWifiManager.setStaConcurrencyForMultiInternetMode(
5905                     WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED);
5906             PollingCheck.check(
5907                     "Wifi multi internet disable failed!", 2_000,
5908                     () -> sWifiManager.getStaConcurrencyForMultiInternetMode()
5909                             == WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED);
5910             // Try to enable multi internet
5911             sWifiManager.setStaConcurrencyForMultiInternetMode(
5912                     WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP);
5913             PollingCheck.check(
5914                     "Wifi multi internet turn on failed!", 2_000,
5915                     () -> sWifiManager.getStaConcurrencyForMultiInternetMode()
5916                             == WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP);
5917         } finally {
5918             uiAutomation.dropShellPermissionIdentity();
5919         }
5920     }
5921 
5922     static class TestWifiNetworkStateChangeListener implements
5923             WifiManager.WifiNetworkStateChangedListener {
5924         final int mCmmRole;
5925         private List<Integer> mStateList = new ArrayList<>();
5926 
TestWifiNetworkStateChangeListener(int cmmRole)5927         TestWifiNetworkStateChangeListener(int cmmRole) {
5928             mCmmRole = cmmRole;
5929         }
5930 
5931         @Override
onWifiNetworkStateChanged(int cmmRole, int state)5932         public void onWifiNetworkStateChanged(int cmmRole, int state) {
5933             if (cmmRole != mCmmRole) {
5934                 return;
5935             }
5936             if (mStateList.contains(state)) {
5937                 // ignore duplicate state transitions
5938                 return;
5939             }
5940             mStateList.add(state);
5941         }
5942 
getStateList()5943         public List<Integer> getStateList() {
5944             return mStateList;
5945         }
5946 
clear()5947         public void clear() {
5948             mStateList.clear();
5949         }
5950     }
5951 
5952     @Test
testWifiNetworkStateChangeListener()5953     public void testWifiNetworkStateChangeListener() throws Exception {
5954         TestWifiNetworkStateChangeListener testListener = new TestWifiNetworkStateChangeListener(
5955                 WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_PRIMARY);
5956         // Verify permission check
5957         assertThrows(SecurityException.class,
5958                 () -> sWifiManager.addWifiNetworkStateChangedListener(mExecutor, testListener));
5959 
5960         // Disable wifi
5961         setWifiEnabled(false);
5962         waitForDisconnection();
5963 
5964         try {
5965             // Register listener then enable wifi
5966             ShellIdentityUtils.invokeWithShellPermissions(
5967                     () -> sWifiManager.addWifiNetworkStateChangedListener(mExecutor, testListener));
5968             setWifiEnabled(true);
5969 
5970             // Trigger a scan & wait for connection to one of the saved networks.
5971             sWifiManager.startScan();
5972             waitForConnection();
5973 
5974             PollingCheck.check(
5975                     "Wifi network state change listener did not receive connected!", 1_000,
5976                     () -> testListener.getStateList().contains(
5977                             WifiManager.WifiNetworkStateChangedListener
5978                                     .WIFI_NETWORK_STATUS_CONNECTED));
5979             int firstState = testListener.getStateList().get(0);
5980             int lastState = testListener.getStateList().get(testListener.getStateList().size() - 1);
5981             assertEquals(WifiManager.WifiNetworkStateChangedListener
5982                     .WIFI_NETWORK_STATUS_CONNECTING, firstState);
5983             assertEquals(WifiManager.WifiNetworkStateChangedListener
5984                     .WIFI_NETWORK_STATUS_CONNECTED, lastState);
5985 
5986             // Disable wifi and verify disconnect is reported.
5987             testListener.clear();
5988             setWifiEnabled(false);
5989             waitForDisconnection();
5990             PollingCheck.check(
5991                     "Wifi network state change listener did not receive disconnected!", 1_000,
5992                     () -> testListener.getStateList().contains(
5993                             WifiManager.WifiNetworkStateChangedListener
5994                                     .WIFI_NETWORK_STATUS_DISCONNECTED));
5995         } finally {
5996             sWifiManager.removeWifiNetworkStateChangedListener(testListener);
5997         }
5998     }
5999 
6000     /**
6001      * Tests {@link WifiConfiguration#setBssidAllowlist(List)}.
6002      */
6003     @Test
testBssidAllowlist()6004     public void testBssidAllowlist() throws Exception {
6005         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6006         List<WifiConfiguration> savedNetworks = null;
6007         try {
6008             uiAutomation.adoptShellPermissionIdentity();
6009 
6010             WifiInfo wifiInfo = sWifiManager.getConnectionInfo();
6011             String connectedBssid = wifiInfo.getBSSID();
6012             int networkId = wifiInfo.getNetworkId();
6013 
6014             // Set empty BSSID allow list to block all APs
6015             savedNetworks = sWifiManager.getConfiguredNetworks();
6016             for (WifiConfiguration network : savedNetworks) {
6017                 network.setBssidAllowlist(Collections.emptyList());
6018                 sWifiManager.updateNetwork(network);
6019             }
6020 
6021             // Disable and re-enable Wifi to avoid reconnect to the secondary candidate
6022             sWifiManager.setWifiEnabled(false);
6023             waitForDisconnection();
6024             sWifiManager.setWifiEnabled(true);
6025             // Now trigger scan and ensure that the device does not connect to any networks.
6026             sWifiManager.startScan();
6027             ensureNotConnected();
6028 
6029             // Set the previous connected BSSID on that network. Other network set with a fake
6030             // (not visible) BSSID only
6031             for (WifiConfiguration network : savedNetworks) {
6032                 if (network.networkId == networkId) {
6033                     network.setBssidAllowlist(List.of(MacAddress.fromString(connectedBssid)));
6034                     sWifiManager.updateNetwork(network);
6035                 } else {
6036                     network.setBssidAllowlist(List.of(MacAddress.fromString(TEST_BSSID)));
6037                     sWifiManager.updateNetwork(network);
6038                 }
6039             }
6040 
6041             // Trigger a scan & wait for connection to one of the saved networks.
6042             sWifiManager.startScan();
6043             waitForConnection();
6044             wifiInfo = sWifiManager.getConnectionInfo();
6045             assertEquals(networkId, wifiInfo.getNetworkId());
6046         } finally {
6047             // Reset BSSID allow list to accept all APs
6048             for (WifiConfiguration network : savedNetworks) {
6049                 assertNotNull(network.getBssidAllowlist());
6050                 network.setBssidAllowlist(null);
6051                 sWifiManager.updateNetwork(network);
6052             }
6053             uiAutomation.dropShellPermissionIdentity();
6054         }
6055     }
6056 
6057     /**
6058      * Tests {@link WifiManager#notifyMinimumRequiredWifiSecurityLevelChanged(int)}
6059      * raise security exception without permission.
6060      */
6061     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
6062     @Test
testNotifyMinimumRequiredWifiSecurityLevelChangedWithoutPermission()6063     public void testNotifyMinimumRequiredWifiSecurityLevelChangedWithoutPermission()
6064             throws Exception {
6065         if (!WifiFeature.isWifiSupported(sContext)) {
6066             // skip the test if WiFi is not supported.
6067             return;
6068         }
6069         assertThrows(SecurityException.class,
6070                 () -> sWifiManager.notifyMinimumRequiredWifiSecurityLevelChanged(
6071                         DevicePolicyManager.WIFI_SECURITY_PERSONAL));
6072     }
6073 
6074     /**
6075      * Tests {@link WifiManager#notifyMinimumRequiredWifiSecurityLevelChanged(int)}
6076      * raise security exception without permission.
6077      */
6078     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
6079     @Test
testNotifyWifiSsidPolicyChangedWithoutPermission()6080     public void testNotifyWifiSsidPolicyChangedWithoutPermission() throws Exception {
6081         if (!WifiFeature.isWifiSupported(sContext)) {
6082             // skip the test if WiFi is not supported.
6083             return;
6084         }
6085         WifiSsidPolicy policy = new WifiSsidPolicy(
6086                 WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, new ArraySet<>(Arrays.asList(
6087                 WifiSsid.fromBytes("ssid".getBytes(StandardCharsets.UTF_8)))));
6088         try {
6089             sWifiManager.notifyWifiSsidPolicyChanged(policy);
6090             fail("Expected security exception due to lack of permission");
6091         } catch (SecurityException e) {
6092             // expected
6093         }
6094     }
6095 
6096     /**
6097      * Verifies that
6098      * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} raises
6099      * a security exception without permission.
6100      */
6101     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
6102     @Test
testIsItPossibleToCreateInterfaceNotAllowed()6103     public void testIsItPossibleToCreateInterfaceNotAllowed() throws Exception {
6104         assertThrows(SecurityException.class, () -> sWifiManager.reportCreateInterfaceImpact(
6105                 WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor,
6106                 (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> {
6107                     // should not get here (security exception!)
6108                 }));
6109     }
6110 
6111     /**
6112      * Verifies
6113      * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} .
6114      */
6115     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
6116     @Test
testIsItPossibleToCreateInterface()6117     public void testIsItPossibleToCreateInterface() throws Exception {
6118         AtomicBoolean called = new AtomicBoolean(false);
6119         AtomicBoolean canBeCreated = new AtomicBoolean(false);
6120         AtomicReference<Set<WifiManager.InterfaceCreationImpact>>
6121                 interfacesWhichWillBeDeleted = new AtomicReference<>(null);
6122         ShellIdentityUtils.invokeWithShellPermissions(
6123                 () -> sWifiManager.reportCreateInterfaceImpact(
6124                         WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor,
6125                         (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> {
6126                             synchronized (mLock) {
6127                                 canBeCreated.set(canBeCreatedLocal);
6128                                 called.set(true);
6129                                 interfacesWhichWillBeDeleted.set(interfacesWhichWillBeDeletedLocal);
6130                                 mLock.notify();
6131                             }
6132                         }));
6133         synchronized (mLock) {
6134             mLock.wait(TEST_WAIT_DURATION_MS);
6135         }
6136         assertTrue(called.get());
6137         if (canBeCreated.get()) {
6138             for (WifiManager.InterfaceCreationImpact entry : interfacesWhichWillBeDeleted.get()) {
6139                 int interfaceType = entry.getInterfaceType();
6140                 assertTrue(interfaceType == WifiManager.WIFI_INTERFACE_TYPE_STA
6141                         || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AP
6142                         || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_DIRECT
6143                         || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AWARE);
6144                 Set<String> packages = entry.getPackages();
6145                 for (String p : packages) {
6146                     assertNotNull(p);
6147                 }
6148             }
6149         }
6150 
6151         // verify the WifiManager.InterfaceCreationImpact APIs
6152         int interfaceType = WifiManager.WIFI_INTERFACE_TYPE_STA;
6153         Set<String> packages = Set.of("package1", "packages2");
6154         WifiManager.InterfaceCreationImpact element = new WifiManager.InterfaceCreationImpact(
6155                 interfaceType, packages);
6156         assertEquals(interfaceType, element.getInterfaceType());
6157         assertEquals(packages, element.getPackages());
6158     }
6159 
6160     /**
6161      * Tests {@link WifiManager#isEasyConnectDppAkmSupported)} does not crash.
6162      */
6163     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
6164     @Test
testIsEasyConnectDppAkmSupported()6165     public void testIsEasyConnectDppAkmSupported() throws Exception {
6166         sWifiManager.isEasyConnectDppAkmSupported();
6167     }
6168 
6169     /**
6170      * Tests {@link WifiManager#getMaxNumberOfChannelsPerNetworkSpecifierRequest)} works
6171      */
6172     @Test
testGetMaxNumberOfChannelsPerNetworkSpecifierRequest()6173     public void testGetMaxNumberOfChannelsPerNetworkSpecifierRequest() {
6174         assertTrue(sWifiManager.getMaxNumberOfChannelsPerNetworkSpecifierRequest() > 0);
6175     }
6176 
6177     /**
6178      * Tests {@link WifiManager#isTlsV13Supported)} does not crash.
6179      */
6180     @Test
testIsTlsV13Supported()6181     public void testIsTlsV13Supported() throws Exception {
6182         sWifiManager.isTlsV13Supported();
6183     }
6184 
6185     /**
6186      * Tests {@link WifiManager#isTlsMinimumVersionSupported)} does not crash.
6187      */
6188     @Test
testIsTlsMinimumVersionSupported()6189     public void testIsTlsMinimumVersionSupported() throws Exception {
6190         sWifiManager.isTlsMinimumVersionSupported();
6191     }
6192 
fillQosPolicyParamsList(List<QosPolicyParams> policyParamsList, int size, boolean uniqueIds)6193     private void fillQosPolicyParamsList(List<QosPolicyParams> policyParamsList,
6194             int size, boolean uniqueIds) {
6195         policyParamsList.clear();
6196         for (int i = 0; i < size; i++) {
6197             int policyId = uniqueIds ? i + 2 : 5;
6198             policyParamsList.add(new QosPolicyParams.Builder(
6199                     policyId, QosPolicyParams.DIRECTION_DOWNLINK)
6200                             .setUserPriority(QosPolicyParams.USER_PRIORITY_VIDEO_LOW)
6201                             .setIpVersion(QosPolicyParams.IP_VERSION_4)
6202                             .build());
6203         }
6204     }
6205 
6206     /**
6207      * Check whether the application QoS feature is enabled.
6208      *
6209      * The feature is enabled if the overlay is true, the experiment feature flag
6210      * is true, and the supplicant service implements V2 of the AIDL interface.
6211      */
applicationQosFeatureEnabled()6212     private boolean applicationQosFeatureEnabled() {
6213         boolean overlayEnabled;
6214         try {
6215             WifiResourceUtil resourceUtil = new WifiResourceUtil(sContext);
6216             overlayEnabled = resourceUtil
6217                     .getWifiBoolean("config_wifiApplicationCentricQosPolicyFeatureEnabled");
6218         } catch (Exception e) {
6219             Log.i(TAG, "Unable to retrieve the QoS overlay value");
6220             return false;
6221         }
6222 
6223         // Supplicant V2 is supported if the vendor partition indicates API > T.
6224         boolean halSupport = PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.TIRAMISU);
6225         boolean featureFlagEnabled = DeviceConfig.getBoolean(DEVICE_CONFIG_NAMESPACE,
6226                 "application_qos_policy_api_enabled", true);
6227 
6228         return overlayEnabled && featureFlagEnabled && halSupport;
6229     }
6230 
6231     /**
6232      * Tests that {@link WifiManager#addQosPolicies(List, Executor, Consumer)},
6233      * {@link WifiManager#removeQosPolicies(int[])}, and
6234      * {@link WifiManager#removeAllQosPolicies()} do not crash.
6235      */
6236     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
6237     @Test
testAddAndRemoveQosPolicies()6238     public void testAddAndRemoveQosPolicies() throws Exception {
6239         final Mutable<Boolean> callbackReceived = new Mutable<Boolean>(false);
6240         final Mutable<Boolean> policiesRejected = new Mutable<Boolean>(true);
6241         Consumer<List<Integer>> listener = new Consumer<List<Integer>>() {
6242             @Override
6243             public void accept(List value) {
6244                 synchronized (mLock) {
6245                     callbackReceived.value = true;
6246                     List<Integer> statusList = value;
6247                     for (Integer status : statusList) {
6248                         if (status != WifiManager.QOS_REQUEST_STATUS_FAILURE_UNKNOWN) {
6249                             policiesRejected.value = false;
6250                             break;
6251                         }
6252                     }
6253                     Log.i(TAG, "Callback received for QoS add request, size=" + statusList.size()
6254                             + ", rejected=" + policiesRejected.value);
6255                     mLock.notify();
6256                 }
6257             }
6258         };
6259 
6260         // Test that invalid inputs trigger an Exception.
6261         final List<QosPolicyParams> policyParamsList = new ArrayList<>();
6262         assertThrows("null executor should trigger exception", NullPointerException.class,
6263                 () -> sWifiManager.addQosPolicies(policyParamsList, null, listener));
6264         assertThrows("null listener should trigger exception", NullPointerException.class,
6265                 () -> sWifiManager.addQosPolicies(policyParamsList, mExecutor, null));
6266         assertThrows("null policy list should trigger exception", NullPointerException.class,
6267                 () -> sWifiManager.addQosPolicies(null, mExecutor, listener));
6268 
6269         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6270         try {
6271             uiAutomation.adoptShellPermissionIdentity();
6272             boolean enabled = applicationQosFeatureEnabled();
6273 
6274             // If the feature is disabled, verify that all policies are rejected.
6275             if (!enabled) {
6276                 Log.i(TAG, "QoS policy APIs are not enabled");
6277                 fillQosPolicyParamsList(policyParamsList, 4, true);
6278                 sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener);
6279                 synchronized (mLock) {
6280                     mLock.wait(TEST_WAIT_DURATION_MS);
6281                 }
6282                 assertTrue(callbackReceived.value);
6283                 assertTrue(policiesRejected.value);
6284                 return;
6285             }
6286 
6287             // Empty params list
6288             assertThrows("empty list should trigger exception", IllegalArgumentException.class,
6289                     () -> sWifiManager.addQosPolicies(new ArrayList<>(), mExecutor, listener));
6290 
6291             // More than {@link WifiManager#getMaxNumberOfPoliciesPerQosRequest()}
6292             // policies in the list
6293             fillQosPolicyParamsList(policyParamsList,
6294                     sWifiManager.getMaxNumberOfPoliciesPerQosRequest() + 1, true);
6295             assertThrows("large list should trigger exception", IllegalArgumentException.class,
6296                     () -> sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener));
6297 
6298             // Params list contains duplicate policy ids
6299             fillQosPolicyParamsList(policyParamsList, 4, false);
6300             assertThrows("duplicate ids should trigger exception", IllegalArgumentException.class,
6301                     () -> sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener));
6302 
6303             // Valid list
6304             fillQosPolicyParamsList(policyParamsList, 4, true);
6305             sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener);
6306 
6307             // sleep to wait for a response from supplicant
6308             synchronized (mLock) {
6309                 mLock.wait(TEST_WAIT_DURATION_MS);
6310             }
6311 
6312             int[] policyIds = new int[policyParamsList.size()];
6313             for (int i = 0; i < policyParamsList.size(); i++) {
6314                 policyIds[i] = policyParamsList.get(i).getPolicyId();
6315             }
6316             sWifiManager.removeQosPolicies(policyIds);
6317 
6318             // sleep to wait for a response from supplicant
6319             synchronized (mLock) {
6320                 mLock.wait(TEST_WAIT_DURATION_MS);
6321             }
6322             sWifiManager.removeAllQosPolicies();
6323         } catch (Exception e) {
6324             fail("addAndRemoveQosPolicy unexpected Exception " + e);
6325         } finally {
6326             uiAutomation.dropShellPermissionIdentity();
6327         }
6328     }
6329 
qosR3Supported()6330     private boolean qosR3Supported() {
6331         return SdkLevel.isAtLeastV() && Flags.androidVWifiApi();
6332     }
6333 
6334     /**
6335      * Tests the builder and get methods for {@link QosPolicyParams}.
6336      */
6337     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
6338     @Test
testQosPolicyParamsBuilder()6339     public void testQosPolicyParamsBuilder() throws Exception {
6340         final int policyId = 5;
6341         final int direction = QosPolicyParams.DIRECTION_DOWNLINK;
6342         final int ipVersion = QosPolicyParams.IP_VERSION_6;
6343         final int dscp = 12;
6344         final int userPriority = QosPolicyParams.USER_PRIORITY_VIDEO_LOW;
6345         final String ipv6Address = "2001:db8:3333:4444:5555:6666:7777:8888";
6346         final InetAddress srcAddr = InetAddress.getByName(ipv6Address);
6347         final InetAddress dstAddr = InetAddress.getByName(ipv6Address);
6348         final int srcPort = 123;
6349         final int protocol = QosPolicyParams.PROTOCOL_TCP;
6350         final int dstPort = 17;
6351         final int[] dstPortRange = new int[]{15, 22};
6352         final byte[] flowLabel = new byte[]{17, 18, 19};
6353 
6354         int minServiceIntervalMicros = 2000;
6355         int maxServiceIntervalMicros = 5000;
6356         int minDataRateKbps = 500;
6357         int delayBoundMicros = 200;
6358         QosCharacteristics qosCharacteristics = new QosCharacteristics.Builder(
6359                 minServiceIntervalMicros, maxServiceIntervalMicros,
6360                 minDataRateKbps, delayBoundMicros).build();
6361 
6362         // Invalid parameter
6363         assertThrows("Invalid dscp should trigger an exception", IllegalArgumentException.class,
6364                 () -> new QosPolicyParams.Builder(policyId, direction)
6365                         .setDscp(70)
6366                         .build());
6367 
6368         // Valid downlink parameters
6369         QosPolicyParams.Builder builder =
6370                 new QosPolicyParams.Builder(policyId, QosPolicyParams.DIRECTION_DOWNLINK)
6371                         .setSourceAddress(srcAddr)
6372                         .setDestinationAddress(dstAddr)
6373                         .setUserPriority(userPriority)
6374                         .setIpVersion(ipVersion)
6375                         .setSourcePort(srcPort)
6376                         .setProtocol(protocol)
6377                         .setDestinationPort(dstPort)
6378                         .setFlowLabel(flowLabel);
6379         if (qosR3Supported()) {
6380             // Optional field for downlink policies
6381             builder.setQosCharacteristics(qosCharacteristics);
6382         }
6383         QosPolicyParams downlinkParams = builder.build();
6384 
6385         assertEquals(policyId, downlinkParams.getPolicyId());
6386         assertEquals(QosPolicyParams.DIRECTION_DOWNLINK, downlinkParams.getDirection());
6387         assertEquals(srcAddr, downlinkParams.getSourceAddress());
6388         assertEquals(dstAddr, downlinkParams.getDestinationAddress());
6389         assertEquals(userPriority, downlinkParams.getUserPriority());
6390         assertEquals(ipVersion, downlinkParams.getIpVersion());
6391         assertEquals(srcPort, downlinkParams.getSourcePort());
6392         assertEquals(protocol, downlinkParams.getProtocol());
6393         assertEquals(dstPort, downlinkParams.getDestinationPort());
6394         assertArrayEquals(flowLabel, downlinkParams.getFlowLabel());
6395         if (qosR3Supported()) {
6396             assertEquals(qosCharacteristics, downlinkParams.getQosCharacteristics());
6397         }
6398 
6399         if (ApiLevelUtil.getApiLevel() == Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
6400             Log.i(TAG, "Uplink policies were not tested, since they are not supported before V");
6401             return;
6402         }
6403 
6404         // Valid uplink parameters
6405         if (qosR3Supported()) {
6406             QosPolicyParams uplinkParams =
6407                 new QosPolicyParams.Builder(policyId, QosPolicyParams.DIRECTION_UPLINK)
6408                             .setSourceAddress(srcAddr)
6409                             .setDestinationAddress(dstAddr)
6410                             .setDscp(dscp)
6411                             .setSourcePort(srcPort)
6412                             .setProtocol(protocol)
6413                             .setDestinationPortRange(dstPortRange[0], dstPortRange[1])
6414                             .setQosCharacteristics(qosCharacteristics)
6415                             .build();
6416             assertEquals(policyId, uplinkParams.getPolicyId());
6417             assertEquals(QosPolicyParams.DIRECTION_UPLINK, uplinkParams.getDirection());
6418             assertEquals(srcAddr, uplinkParams.getSourceAddress());
6419             assertEquals(dstAddr, uplinkParams.getDestinationAddress());
6420             assertEquals(dscp, uplinkParams.getDscp());
6421             assertEquals(srcPort, uplinkParams.getSourcePort());
6422             assertEquals(protocol, uplinkParams.getProtocol());
6423             assertArrayEquals(dstPortRange, uplinkParams.getDestinationPortRange());
6424             assertEquals(qosCharacteristics, uplinkParams.getQosCharacteristics());
6425         }
6426     }
6427 
6428     /**
6429      * Verifies when the link layer stats polling interval is overridden by
6430      * {@link WifiManager#setLinkLayerStatsPollingInterval(int)},
6431      * the new interval is set correctly by checking
6432      * {@link WifiManager#getLinkLayerStatsPollingInterval(Executor, Consumer)}
6433      */
6434     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
6435     @Test
testSetAndGetLinkLayerStatsPollingInterval()6436     public void testSetAndGetLinkLayerStatsPollingInterval() throws Exception {
6437         AtomicInteger currentInterval = new AtomicInteger(-1);
6438         Consumer<Integer> listener = new Consumer<Integer>() {
6439             @Override
6440             public void accept(Integer value) {
6441                 synchronized (mLock) {
6442                     currentInterval.set(value);
6443                     mLock.notify();
6444                 }
6445             }
6446         };
6447 
6448         // SecurityException
6449         assertThrows(SecurityException.class,
6450                 () -> sWifiManager.setLinkLayerStatsPollingInterval(
6451                         TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS));
6452         assertThrows(SecurityException.class,
6453                 () -> sWifiManager.getLinkLayerStatsPollingInterval(mExecutor, listener));
6454         // null executor
6455         assertThrows("null executor should trigger exception", NullPointerException.class,
6456                 () -> sWifiManager.getLinkLayerStatsPollingInterval(null, listener));
6457         // null listener
6458         assertThrows("null listener should trigger exception", NullPointerException.class,
6459                 () -> sWifiManager.getLinkLayerStatsPollingInterval(mExecutor, null));
6460 
6461         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6462 
6463         try {
6464             uiAutomation.adoptShellPermissionIdentity();
6465             assertThrows(IllegalArgumentException.class,
6466                     () -> sWifiManager.setLinkLayerStatsPollingInterval(
6467                             -TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS));
6468             sWifiManager.setLinkLayerStatsPollingInterval(
6469                     TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS);
6470             sWifiManager.getLinkLayerStatsPollingInterval(mExecutor, listener);
6471             synchronized (mLock) {
6472                 mLock.wait(TEST_WAIT_DURATION_MS);
6473             }
6474             assertEquals(TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS, currentInterval.get());
6475             // set the interval to automatic handling after the test
6476             sWifiManager.setLinkLayerStatsPollingInterval(0);
6477         } catch (UnsupportedOperationException ex) {
6478             // Expected if the device does not support this API
6479         } catch (Exception e) {
6480             fail("setLinkLayerStatsPollingInterval / getLinkLayerStatsPollingInterval "
6481                     + "unexpected Exception " + e);
6482         } finally {
6483             uiAutomation.dropShellPermissionIdentity();
6484         }
6485     }
6486 
6487     /**
6488      * Tests {@link WifiManager#getMaxMloAssociationLinkCount(Executor, Consumer)} and
6489      * {@link WifiManager#getMaxMloStrLinkCount(Executor, Consumer)}.
6490      */
6491     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
6492     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6493     @Test
testMloCapabilities()6494     public void testMloCapabilities() throws Exception {
6495         AtomicInteger linkCount = new AtomicInteger();
6496         Consumer<Integer> getListener = new Consumer<Integer>() {
6497             @Override
6498             public void accept(Integer value) {
6499                 synchronized (mLock) {
6500                     linkCount.set(value);
6501                     mLock.notify();
6502                 }
6503             }
6504         };
6505 
6506         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6507         try {
6508             uiAutomation.adoptShellPermissionIdentity();
6509             // Test that invalid inputs trigger an exception.
6510             assertThrows("null executor should trigger exception", NullPointerException.class,
6511                     () -> sWifiManager.getMaxMloAssociationLinkCount(null, getListener));
6512             assertThrows("null listener should trigger exception", NullPointerException.class,
6513                     () -> sWifiManager.getMaxMloAssociationLinkCount(mExecutor, null));
6514             assertThrows("null executor should trigger exception", NullPointerException.class,
6515                     () -> sWifiManager.getMaxMloStrLinkCount(null, getListener));
6516             assertThrows("null listener should trigger exception", NullPointerException.class,
6517                     () -> sWifiManager.getMaxMloStrLinkCount(mExecutor, null));
6518 
6519             linkCount.set(Integer.MIN_VALUE);
6520             sWifiManager.getMaxMloStrLinkCount(mExecutor, getListener);
6521             PollingCheck.check("getMaxMloStrLinkCount failed", TEST_WAIT_DURATION_MS,
6522                     () -> (linkCount.get() >= -1));
6523 
6524             linkCount.set(Integer.MIN_VALUE);
6525             sWifiManager.getMaxMloAssociationLinkCount(mExecutor, getListener);
6526             PollingCheck.check("getMaxMloAssociationLinkCount failed", TEST_WAIT_DURATION_MS,
6527                     () -> (linkCount.get() >= -1));
6528         } catch (Exception e) {
6529             fail("Unexpected exception " + e);
6530         } finally {
6531             uiAutomation.dropShellPermissionIdentity();
6532         }
6533     }
6534     /**
6535      * Tests {@link WifiManager#setLinkMode} and {@link WifiManager#getLinkMode} works
6536      */
6537     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
6538     @Test
testMloMode()6539     public void testMloMode() {
6540         // Get listener.
6541         AtomicInteger getMode = new AtomicInteger();
6542         Consumer<Integer> getListener = new Consumer<Integer>() {
6543             @Override
6544             public void accept(Integer value) {
6545                 synchronized (mLock) {
6546                     getMode.set(value);
6547                     mLock.notify();
6548                 }
6549             }
6550         };
6551         // Set listener.
6552         AtomicBoolean setStatus = new AtomicBoolean();
6553         Consumer<Boolean> setListener = new Consumer<Boolean>() {
6554             @Override
6555             public void accept(Boolean value) {
6556                 synchronized (mLock) {
6557                     setStatus.set(value);
6558                     mLock.notify();
6559                 }
6560             }
6561         };
6562         // Test that invalid inputs trigger an exception.
6563         assertThrows("null executor should trigger exception", NullPointerException.class,
6564                 () -> sWifiManager.setMloMode(WifiManager.MLO_MODE_DEFAULT, null, setListener));
6565         assertThrows("null listener should trigger exception", NullPointerException.class,
6566                 () -> sWifiManager.setMloMode(WifiManager.MLO_MODE_DEFAULT, mExecutor, null));
6567         assertThrows("null executor should trigger exception", NullPointerException.class,
6568                 () -> sWifiManager.getMloMode(null, getListener));
6569         assertThrows("null listener should trigger exception", NullPointerException.class,
6570                 () -> sWifiManager.getMloMode(mExecutor, null));
6571 
6572         // Test that invalid inputs trigger an IllegalArgumentException.
6573         assertThrows("Invalid mode", IllegalArgumentException.class,
6574                 () -> sWifiManager.setMloMode(-1, mExecutor, setListener));
6575         assertThrows("Invalid mode", IllegalArgumentException.class,
6576                 () -> sWifiManager.setMloMode(1000, mExecutor, setListener));
6577 
6578         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6579         // Test set if supported.
6580         try {
6581             uiAutomation.adoptShellPermissionIdentity();
6582             // Check getMloMode() returns values in range.
6583             sWifiManager.getMloMode(mExecutor, getListener);
6584             assertThat(getMode.get()).isIn(Range.closed(WifiManager.MLO_MODE_DEFAULT,
6585                     WifiManager.MLO_MODE_LOW_POWER));
6586             // Try to set default MLO mode and get.
6587             sWifiManager.setMloMode(WifiManager.MLO_MODE_DEFAULT, mExecutor, setListener);
6588             if (setStatus.get()) {
6589                 sWifiManager.getMloMode(mExecutor, getListener);
6590                 assertTrue(getMode.get() == WifiManager.MLO_MODE_DEFAULT);
6591             }
6592             // Try to set low latency MLO mode and get.
6593             sWifiManager.setMloMode(WifiManager.MLO_MODE_LOW_LATENCY, mExecutor, setListener);
6594             if (setStatus.get()) {
6595                 sWifiManager.getMloMode(mExecutor, getListener);
6596                 assertTrue(getMode.get() == WifiManager.MLO_MODE_LOW_LATENCY);
6597             }
6598             // Try to set high throughput MLO mode and get.
6599             sWifiManager.setMloMode(WifiManager.MLO_MODE_HIGH_THROUGHPUT, mExecutor, setListener);
6600             if (setStatus.get()) {
6601                 sWifiManager.getMloMode(mExecutor, getListener);
6602                 assertTrue(getMode.get() == WifiManager.MLO_MODE_DEFAULT);
6603             }
6604             // Try to set low power MLO mode and get.
6605             sWifiManager.setMloMode(WifiManager.MLO_MODE_LOW_POWER, mExecutor, setListener);
6606             if (setStatus.get()) {
6607                 sWifiManager.getMloMode(mExecutor, getListener);
6608                 assertTrue(getMode.get() == WifiManager.MLO_MODE_DEFAULT);
6609             }
6610         } catch (Exception e) {
6611             fail("Unexpected exception " + e);
6612         } finally {
6613             uiAutomation.dropShellPermissionIdentity();
6614         }
6615     }
6616 
6617     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
6618     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6619     @Test
testGetSupportedSimultaneousBandCombinations()6620     public void testGetSupportedSimultaneousBandCombinations() {
6621         AtomicInteger nEntries = new AtomicInteger();
6622         Consumer<List<int[]>> getListener = new Consumer<List<int[]>>() {
6623             @Override
6624             public void accept(List<int[]> bands) {
6625                 synchronized (mLock) {
6626                     nEntries.set(bands.size());
6627                     mLock.notify();
6628                 }
6629             }
6630         };
6631         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6632         try {
6633             uiAutomation.adoptShellPermissionIdentity();
6634 
6635             assertThrows("null executor should trigger exception", NullPointerException.class,
6636                     () -> sWifiManager.getSupportedSimultaneousBandCombinations(null, getListener));
6637             assertThrows("null listener should trigger exception", NullPointerException.class,
6638                     () -> sWifiManager.getSupportedSimultaneousBandCombinations(mExecutor, null));
6639 
6640             nEntries.set(-1);
6641             sWifiManager.getSupportedSimultaneousBandCombinations(mExecutor, getListener);
6642             PollingCheck.check("getSupportedSimultaneousBandCombinations failed",
6643                     TEST_WAIT_DURATION_MS,
6644                     () -> (nEntries.get() > -1));
6645         } catch (Exception e) {
6646             fail("Unexpected exception " + e);
6647         } finally {
6648             uiAutomation.dropShellPermissionIdentity();
6649         }
6650     }
6651 
6652     /**
6653      * Tests {@link WifiManager#isThirdPartyAppEnablingWifiConfirmationDialogEnabled()}
6654      * and {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)}
6655      */
6656     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
6657     @Test
testGetAndSetThirdPartyAppEnablingWifiConfirmationDialogEnabled()6658     public void testGetAndSetThirdPartyAppEnablingWifiConfirmationDialogEnabled() {
6659         // Expect a SecurityException without the required permissions.
6660         assertThrows(SecurityException.class,
6661                 () -> sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled());
6662         assertThrows(SecurityException.class,
6663                 () -> sWifiManager.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(true));
6664 
6665         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6666         try {
6667             uiAutomation.adoptShellPermissionIdentity();
6668 
6669             // Store a new value.
6670             boolean defaultVal =
6671                     sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled();
6672             boolean newVal = !defaultVal;
6673             sWifiManager.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(newVal);
6674             assertEquals(newVal,
6675                     sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled());
6676 
6677             // Restore the original value.
6678             sWifiManager.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(defaultVal);
6679             assertEquals(defaultVal,
6680                     sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled());
6681         } catch (Exception e) {
6682             fail("Unexpected exception " + e);
6683         } finally {
6684             uiAutomation.dropShellPermissionIdentity();
6685         }
6686     }
6687 
6688     static class TestWifiLowLatencyLockListener implements WifiManager.WifiLowLatencyLockListener {
6689         private boolean mIsActivated = false;
6690         private int[] mOwnerUids = null;
6691         private int[] mActiveUids = null;
6692 
clear()6693         public void clear() {
6694             mIsActivated = false;
6695             mOwnerUids = null;
6696             mActiveUids = null;
6697         }
6698 
6699         @Override
onActivatedStateChanged(boolean activated)6700         public void onActivatedStateChanged(boolean activated) {
6701             mIsActivated = activated;
6702         }
6703 
6704         @Override
onOwnershipChanged(@onNull int[] ownerUids)6705         public void onOwnershipChanged(@NonNull int[] ownerUids) {
6706             mOwnerUids = ownerUids;
6707         }
6708 
6709         @Override
onActiveUsersChanged(@onNull int[] activeUids)6710         public void onActiveUsersChanged(@NonNull int[] activeUids) {
6711             mActiveUids = activeUids;
6712         }
6713 
isActivated()6714         public boolean isActivated() {
6715             return mIsActivated;
6716         }
6717 
isLockOwned(int myUid)6718         public boolean isLockOwned(int myUid) {
6719             if (mOwnerUids == null) return false;
6720             for (int uid : mOwnerUids) {
6721                 if (uid == myUid) return true;
6722             }
6723             return false;
6724         }
6725 
isActiveLockUser(int myUid)6726         public boolean isActiveLockUser(int myUid) {
6727             if (mActiveUids == null) return false;
6728             for (int uid : mActiveUids) {
6729                 if (uid == myUid) return true;
6730             }
6731             return false;
6732         }
6733     }
6734 
6735     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
6736     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6737     @Test
testWifiLowLatencyLockListener()6738     public void testWifiLowLatencyLockListener() throws Exception {
6739         TestWifiLowLatencyLockListener testListener = new TestWifiLowLatencyLockListener();
6740         // Verify permission check
6741         assertThrows(SecurityException.class,
6742                 () -> sWifiManager.addWifiLowLatencyLockListener(mExecutor, testListener));
6743 
6744         // Disable wifi
6745         setWifiEnabled(false);
6746         waitForDisconnection();
6747 
6748         WifiLock wifiLowLatencyLock = sWifiManager.createWifiLock(
6749                 WifiManager.WIFI_MODE_FULL_LOW_LATENCY,
6750                 TAG);
6751 
6752         try {
6753             // Register listener then enable wifi
6754             ShellIdentityUtils.invokeWithShellPermissions(
6755                     () -> sWifiManager.addWifiLowLatencyLockListener(mExecutor, testListener));
6756             setWifiEnabled(true);
6757 
6758             // Trigger a scan & wait for connection to one of the saved networks.
6759             sWifiManager.startScan();
6760             waitForConnection();
6761 
6762             // TODO: b/281356259 - Move this to a foreground activity.
6763             ShellIdentityUtils.invokeWithShellPermissions(() -> wifiLowLatencyLock.acquire());
6764 
6765             if (sWifiManager.isLowLatencyModeSupported()) {
6766                 PollingCheck.check("Lock is not activated!", 1_000,
6767                         () -> testListener.isActivated());
6768             }
6769 
6770             PollingCheck.check("Lock is not owned!", 1_000,
6771                     () -> testListener.isLockOwned(myUid()));
6772 
6773             if (sWifiManager.isLowLatencyModeSupported()) {
6774                 PollingCheck.check("Not an active Lock user!", 1_000,
6775                         () -> testListener.isActiveLockUser(myUid()));
6776             }
6777 
6778             ShellIdentityUtils.invokeWithShellPermissions(() -> wifiLowLatencyLock.release());
6779 
6780             // Note: The lock cannot be tested for deactivation after release because other
6781             // applications can still keep it active.
6782 
6783             PollingCheck.check("Still owns the Lock after release!", 1_000,
6784                     () -> !testListener.isLockOwned(myUid()));
6785         } catch (Exception e) {
6786             fail("Unexpected exception " + e);
6787         } finally {
6788             testListener.clear();
6789             sWifiManager.removeWifiLowLatencyLockListener(testListener);
6790         }
6791     }
6792 
6793     /**
6794      * Tests the builder and get methods for {@link OuiKeyedData}.
6795      */
6796     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6797     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM,
6798                  codeName = "VanillaIceCream")
6799     @Test
testOuiKeyedDataBuilder()6800     public void testOuiKeyedDataBuilder() throws Exception {
6801         int oui = 0x00112233;
6802         PersistableBundle data = new PersistableBundle();
6803         String key = "intField";
6804         data.putInt(key, 12345);
6805 
6806         assertThrows("Zero OUI should trigger an exception", IllegalArgumentException.class,
6807                 () -> new OuiKeyedData.Builder(0, data).build());
6808         assertThrows(">24-bit OUI should trigger an exception", IllegalArgumentException.class,
6809                 () -> new OuiKeyedData.Builder(0x11223344, data).build());
6810         assertThrows("Null data should trigger an exception", IllegalArgumentException.class,
6811                 () -> new OuiKeyedData.Builder(oui, null).build());
6812 
6813         OuiKeyedData ouiKeyedData = new OuiKeyedData.Builder(oui, data).build();
6814         assertEquals(oui, ouiKeyedData.getOui());
6815         assertTrue(data.keySet().equals(ouiKeyedData.getData().keySet()));
6816         assertEquals(data.getInt(key), ouiKeyedData.getData().getInt(key));
6817     }
6818 
6819     /**
6820      * Tests {@link WifiManager#isWepSupported()} does not crash.
6821      */
6822     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6823     @Test
testIsWepSupported()6824     public void testIsWepSupported() throws Exception {
6825         sWifiManager.isWepSupported();
6826     }
6827 
6828     /**
6829      * Tests {@link WifiManager#isWpaPersonalSupported()} does not crash.
6830      */
6831     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6832     @Test
testIsWpaPersonalSupported()6833     public void testIsWpaPersonalSupported() throws Exception {
6834         sWifiManager.isWpaPersonalSupported();
6835     }
6836 
6837     /**
6838      * Tests {@link WifiManager#setWepAllowed()} and
6839      * {@link WifiManager#queryWepAllowed()}.
6840      */
6841     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6842     @Test
testSetAndQueryWepAllowed()6843     public void testSetAndQueryWepAllowed() throws Exception {
6844         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6845         Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false);
6846         boolean currentWepAllowed = false;
6847         boolean isRestoreRequired = false;
6848         long now, deadline;
6849         try {
6850             uiAutomation.adoptShellPermissionIdentity();
6851             Mutable<Boolean> isWepAllowed = new Mutable<Boolean>(false);
6852             sWifiManager.queryWepAllowed(mExecutor,
6853                     new Consumer<Boolean>() {
6854                     @Override
6855                     public void accept(Boolean value) {
6856                         synchronized (mLock) {
6857                             isWepAllowed.value = value;
6858                             isQuerySucceeded.value = true;
6859                             mLock.notify();
6860                         }
6861                     }
6862                 });
6863             synchronized (mLock) {
6864                 now = System.currentTimeMillis();
6865                 deadline = now + TEST_WAIT_DURATION_MS;
6866                 while (!isQuerySucceeded.value && now < deadline) {
6867                     mLock.wait(deadline - now);
6868                     now = System.currentTimeMillis();
6869                 }
6870             }
6871             assertTrue(isQuerySucceeded.value);
6872             // Reset for next query
6873             isQuerySucceeded.value = false;
6874             currentWepAllowed = isWepAllowed.value;
6875             isRestoreRequired = true;
6876             sWifiManager.setWepAllowed(!currentWepAllowed);
6877             sWifiManager.queryWepAllowed(mExecutor,
6878                     new Consumer<Boolean>() {
6879                     @Override
6880                     public void accept(Boolean value) {
6881                         synchronized (mLock) {
6882                             isWepAllowed.value = value;
6883                             isQuerySucceeded.value = true;
6884                             mLock.notify();
6885                         }
6886                     }
6887                 });
6888             synchronized (mLock) {
6889                 now = System.currentTimeMillis();
6890                 deadline = now + TEST_WAIT_DURATION_MS;
6891                 while (!isQuerySucceeded.value && now < deadline) {
6892                     mLock.wait(deadline - now);
6893                     now = System.currentTimeMillis();
6894                 }
6895             }
6896             assertEquals(isWepAllowed.value, !currentWepAllowed);
6897         } finally {
6898             if (isRestoreRequired) {
6899                 sWifiManager.setWepAllowed(currentWepAllowed);
6900             }
6901             uiAutomation.dropShellPermissionIdentity();
6902         }
6903     }
6904 
6905     /**
6906      * Tests {@link WifiManager#enableMscs(MscsParams)}, {@link WifiManager#disableMscs()},
6907      * and all get/set methods in {@link MscsParams}.
6908      */
6909     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6910     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM,
6911             codeName = "VanillaIceCream")
6912     @Test
testEnableAndDisableMscs()6913     public void testEnableAndDisableMscs() {
6914         int frameClassifierFields = MscsParams.FRAME_CLASSIFIER_IP_VERSION;
6915         int userPriorityBitmap = 0; // don't match any user priorities using MSCS
6916         int userPriorityLimit = 7;
6917         int streamTimeoutUs = 30000000; // 30 seconds (value is longer than TEST_WAIT_DURATION_MS)
6918         MscsParams params = new MscsParams.Builder()
6919                 .setFrameClassifierFields(frameClassifierFields)
6920                 .setUserPriorityBitmap(userPriorityBitmap)
6921                 .setUserPriorityLimit(userPriorityLimit)
6922                 .setStreamTimeoutUs(streamTimeoutUs)
6923                 .build();
6924         assertEquals(frameClassifierFields, params.getFrameClassifierFields());
6925         assertEquals(userPriorityBitmap, params.getUserPriorityBitmap());
6926         assertEquals(userPriorityLimit, params.getUserPriorityLimit());
6927         assertEquals(streamTimeoutUs, params.getStreamTimeoutUs());
6928 
6929         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
6930         try {
6931             uiAutomation.adoptShellPermissionIdentity();
6932             sWifiManager.enableMscs(params);
6933             synchronized (mLock) {
6934                 // Wait for the request to get sent to the AP.
6935                 mLock.wait(TEST_WAIT_DURATION_MS);
6936             }
6937             sWifiManager.disableMscs();
6938         } catch (Exception e) {
6939             fail("testEnableAndDisableMscs encountered an exception: " + e);
6940         } finally {
6941             uiAutomation.dropShellPermissionIdentity();
6942         }
6943     }
6944 
6945     /**
6946      * Tests the result from {@link WifiUriParser#parseUri(String)} can be added.
6947      */
6948     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6949     @Test
testZxingNetworkFromUriParserCanBeAdded()6950     public void testZxingNetworkFromUriParserCanBeAdded() throws Exception {
6951         String testUriZx = "WIFI:S:testAbC;T:nopass";
6952         UriParserResults result = WifiUriParser.parseUri(testUriZx);
6953         assertNotNull(result);
6954         assertEquals(result.getUriScheme(), UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG);
6955         WifiConfiguration config = result.getWifiConfiguration();
6956         assertNotNull(config);
6957         // These below API's only work with privileged permissions (obtained via shell identity
6958         // for test)
6959         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
6960                 .getUiAutomation();
6961         int networkId = INVALID_NETWORK_ID;
6962         try {
6963             uiAutomation.adoptShellPermissionIdentity();
6964             // Verify that the network is added
6965             networkId = sWifiManager.addNetwork(config);
6966             assertNotEquals(INVALID_NETWORK_ID, networkId);
6967         } finally {
6968             if (networkId != INVALID_NETWORK_ID) {
6969                 // Clean up the previously added network
6970                 sWifiManager.removeNetwork(networkId);
6971             }
6972             uiAutomation.dropShellPermissionIdentity();
6973         }
6974     }
6975 
6976     /*
6977      * Tests the builder and get methods for {@link QosCharacteristics}.
6978      */
6979     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
6980     @Test
testQosCharacteristicsBuilder()6981     public void testQosCharacteristicsBuilder() {
6982         int minServiceIntervalMicros = 2000;
6983         int maxServiceIntervalMicros = 5000;
6984         int minDataRateKbps = 500;
6985         int delayBoundMicros = 200;
6986         int maxMsduSizeOctets = 4;
6987         int serviceStartTimeMicros = 250;
6988         int serviceStartTimeLinkId = 0x5;
6989         int meanDataRateKbps = 1500;
6990         int burstSizeOctets = 2;
6991         int msduLifetimeMillis = 400;
6992         int deliveryRatio = QosCharacteristics.DELIVERY_RATIO_99;
6993         int countExponent = 5;
6994 
6995         QosCharacteristics qosCharacteristics = new QosCharacteristics.Builder(
6996                 minServiceIntervalMicros, maxServiceIntervalMicros,
6997                 minDataRateKbps, delayBoundMicros)
6998                 .setBurstSizeOctets(burstSizeOctets)
6999                 .setMaxMsduSizeOctets(maxMsduSizeOctets)
7000                 .setServiceStartTimeInfo(serviceStartTimeMicros, serviceStartTimeLinkId)
7001                 .setMeanDataRateKbps(meanDataRateKbps)
7002                 .setMsduLifetimeMillis(msduLifetimeMillis)
7003                 .setMsduDeliveryInfo(deliveryRatio, countExponent)
7004                 .build();
7005 
7006         assertEquals(minServiceIntervalMicros, qosCharacteristics.getMinServiceIntervalMicros());
7007         assertEquals(maxServiceIntervalMicros, qosCharacteristics.getMaxServiceIntervalMicros());
7008         assertEquals(minDataRateKbps, qosCharacteristics.getMinDataRateKbps());
7009         assertEquals(delayBoundMicros, qosCharacteristics.getDelayBoundMicros());
7010         assertEquals(maxMsduSizeOctets, qosCharacteristics.getMaxMsduSizeOctets());
7011         assertEquals(serviceStartTimeMicros, qosCharacteristics.getServiceStartTimeMicros());
7012         assertEquals(serviceStartTimeLinkId, qosCharacteristics.getServiceStartTimeLinkId());
7013         assertEquals(meanDataRateKbps, qosCharacteristics.getMeanDataRateKbps());
7014         assertEquals(burstSizeOctets, qosCharacteristics.getBurstSizeOctets());
7015         assertEquals(msduLifetimeMillis, qosCharacteristics.getMsduLifetimeMillis());
7016         assertEquals(deliveryRatio, qosCharacteristics.getDeliveryRatio());
7017         assertEquals(countExponent, qosCharacteristics.getCountExponent());
7018     }
7019 
querySendDhcpHostnameRestrictionSynchronous()7020     private int querySendDhcpHostnameRestrictionSynchronous() throws Exception {
7021         Mutable<Integer> queriedRestriction = new Mutable<>(0);
7022         Mutable<Boolean> isQuerySucceeded = new Mutable<>(false);
7023         sWifiManager.querySendDhcpHostnameRestriction(mExecutor, (value) -> {
7024             synchronized (mLock) {
7025                 queriedRestriction.value = value;
7026                 isQuerySucceeded.value = true;
7027                 mLock.notify();
7028             }
7029         });
7030         synchronized (mLock) {
7031             long now = System.currentTimeMillis();
7032             long deadline = now + TEST_WAIT_DURATION_MS;
7033             while (!isQuerySucceeded.value && now < deadline) {
7034                 mLock.wait(deadline - now);
7035                 now = System.currentTimeMillis();
7036             }
7037         }
7038         assertTrue(isQuerySucceeded.value);
7039         return queriedRestriction.value;
7040     }
7041 
7042     /**
7043      * Tests {@link WifiManager#setSendDhcpHostnameRestriction(int)} and
7044      * {@link WifiManager#querySendDhcpHostnameRestriction(Executor, IntConsumer)}.
7045      */
7046     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
7047     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM,
7048             codeName = "VanillaIceCream")
7049     @Test
testSetAndQuerySendDhcpHostnameRestriction()7050     public void testSetAndQuerySendDhcpHostnameRestriction() throws Exception {
7051         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
7052         int previousRestriction = 0;
7053         boolean isRestoreRequired = false;
7054         try {
7055             uiAutomation.adoptShellPermissionIdentity();
7056             previousRestriction = querySendDhcpHostnameRestrictionSynchronous();
7057 
7058             sWifiManager.setSendDhcpHostnameRestriction(
7059                     WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN);
7060             isRestoreRequired = true;
7061             assertEquals(querySendDhcpHostnameRestrictionSynchronous(),
7062                     WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN);
7063 
7064             sWifiManager.setSendDhcpHostnameRestriction(
7065                     WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN
7066                             | WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE);
7067             assertEquals(querySendDhcpHostnameRestrictionSynchronous(),
7068                     WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN
7069                             | WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE);
7070         } finally {
7071             if (isRestoreRequired) {
7072                 sWifiManager.setSendDhcpHostnameRestriction(previousRestriction);
7073             }
7074             uiAutomation.dropShellPermissionIdentity();
7075         }
7076     }
7077 
7078     /**
7079      * Tests {@link WifiConfiguration#setWifi7Enabled(boolean)}. Validate default behavior, disable
7080      * Wi-Fi 7 and Enable Wi-Fi 7.
7081      */
7082     @ApiTest(apis = {"android.net.wifi.WifiConfiguration#setWifi7Enabled",
7083             "android.net.wifi.WifiConfiguration#isWifi7Enabled"})
7084     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
7085     @Test
testEnableWifi7()7086     public void testEnableWifi7() throws Exception {
7087         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
7088         TestActionListener actionListener = new TestActionListener(mLock);
7089         setWifiEnabled(true);
7090         WifiConfiguration wifi7Network = null;
7091         try {
7092             uiAutomation.adoptShellPermissionIdentity();
7093             // Make sure device supports Wi-Fi 7
7094             assumeTrue(sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE));
7095 
7096             List<WifiConfiguration> savedNetworks = sWifiManager.getConfiguredNetworks();
7097             wifi7Network = TestHelper.findFirstAvailableSavedNetwork(sWifiManager,
7098                     savedNetworks, TestHelper.AP_CAPABILITY_BIT_WIFI7);
7099             // TODO: b/322011012
7100             assumeTrue("Unable to locate Wi-Fi 7 networks in range.\n", wifi7Network != null);
7101 
7102             // Default behavior: check new connection is Wi-Fi 7
7103             sWifiManager.disconnect();
7104             waitForDisconnection();
7105             assertTrue(wifi7Network.isWifi7Enabled());
7106             sWifiManager.connect(wifi7Network.networkId, actionListener);
7107             waitForConnection();
7108             assertTrue(sWifiManager.getConnectionInfo().getWifiStandard()
7109                     == ScanResult.WIFI_STANDARD_11BE);
7110 
7111             // Disable Wi-Fi 7 while connected: check new connection is not Wi-Fi 7
7112             wifi7Network.setWifi7Enabled(false);
7113             assertFalse(wifi7Network.isWifi7Enabled());
7114             sWifiManager.updateNetwork(wifi7Network);
7115             waitForConnection();
7116             assertTrue(sWifiManager.getConnectionInfo().getWifiStandard()
7117                     != ScanResult.WIFI_STANDARD_11BE);
7118 
7119             // Enable Wi-Fi 7: check new connection is Wi-Fi 7
7120             sWifiManager.disconnect();
7121             waitForDisconnection();
7122             wifi7Network.setWifi7Enabled(true);
7123             assertTrue(wifi7Network.isWifi7Enabled());
7124             sWifiManager.connect(wifi7Network.networkId, actionListener);
7125             waitForConnection();
7126             assertTrue(sWifiManager.getConnectionInfo().getWifiStandard()
7127                     == ScanResult.WIFI_STANDARD_11BE);
7128 
7129         } finally {
7130             // Restore
7131             if (wifi7Network != null) {
7132                 wifi7Network.setWifi7Enabled(true);
7133             }
7134             uiAutomation.dropShellPermissionIdentity();
7135         }
7136     }
7137 
7138     class TestTwtSessionCallback implements TwtSessionCallback {
7139         final AtomicReference<TwtSession> mTwtSession = new AtomicReference<>();
7140         final AtomicInteger mTwtTeardownReasonCode = new AtomicInteger(-1);
7141         final AtomicInteger mTwtErrorCode = new AtomicInteger(-1);
7142 
7143         @Override
onFailure(int errorCode)7144         public void onFailure(int errorCode) {
7145             synchronized (mLock) {
7146                 mTwtErrorCode.set(errorCode);
7147                 mLock.notify();
7148             }
7149         }
7150 
7151         @Override
onTeardown(int reasonCode)7152         public void onTeardown(int reasonCode) {
7153             synchronized (mLock) {
7154                 mTwtTeardownReasonCode.set(reasonCode);
7155                 mLock.notify();
7156             }
7157         }
7158 
7159         @Override
onCreate(TwtSession twtSession)7160         public void onCreate(TwtSession twtSession) {
7161             synchronized (mLock) {
7162                 mTwtSession.set(twtSession);
7163             }
7164         }
7165     }
7166 
7167     /**
7168      * Validate setting up a TWT session if device supports and get stats and finally close. If the
7169      * connection is multi-link, pick the first link and set up the TWT session.
7170      */
7171     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
7172     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName =
7173             "VanillaIceCream")
7174     @Test
7175     @ApiTest(apis = {"android.net.wifi.WifiManager#getTwtCapabilities",
7176             "android.net.wifi.WifiManager#twtSessionSetup",
7177             "android.net.wifi.twt.TwtSession#getStats",
7178             "android.net.wifi.twt.TwtSession#teardown",
7179             "android.net.wifi.twt.TwtSession#getWakeDurationMicros",
7180             "android.net.wifi.twt.TwtSession#getWakeIntervalMicros",
7181             "android.net.wifi.twt.TwtSession#getMloLinkId",
7182             "android.net.wifi.twt.TwtRequest#Builder",
7183             "android.net.wifi.twt.TwtRequest.Builder#setLinkId",
7184             "android.net.wifi.twt.TwtRequest#getMinWakeDurationMicros",
7185             "android.net.wifi.twt.TwtRequest#getMaxWakeDurationMicros",
7186             "android.net.wifi.twt.TwtRequest#getMinWakeIntervalMicros",
7187             "android.net.wifi.twt.TwtRequest#getMaxWakeIntervalMicros",
7188             "android.net.wifi.twt.TwtRequest#getLinkId"})
testTwt()7189     public void testTwt() throws Exception {
7190         AtomicReference<Bundle> twtCapabilities = new AtomicReference<>();
7191         AtomicReference<Bundle> twtStats = new AtomicReference<>();
7192         long now, deadline;
7193         Consumer<Bundle> twtCapabilityCallback = capabilities -> {
7194             synchronized (mLock) {
7195                 twtCapabilities.set(capabilities);
7196                 mLock.notify();
7197             }
7198         };
7199         Consumer<Bundle> twtStatsCallback = stats -> {
7200             synchronized (mLock) {
7201                 twtStats.set(stats);
7202                 mLock.notify();
7203             }
7204         };
7205         TestTwtSessionCallback testTwtSessionCallback = new TestTwtSessionCallback();
7206         TestActionListener actionListener = new TestActionListener(mLock);
7207         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
7208 
7209         try {
7210             uiAutomation.adoptShellPermissionIdentity();
7211             sWifiManager.getTwtCapabilities(mExecutor, twtCapabilityCallback);
7212             synchronized (mLock) {
7213                 now = System.currentTimeMillis();
7214                 deadline = now + TEST_WAIT_DURATION_MS;
7215                 while (twtCapabilities.get() == null && now < deadline) {
7216                     mLock.wait(deadline - now);
7217                     now = System.currentTimeMillis();
7218                 }
7219             }
7220             assertNotNull("getTwtCapabilities() timed out !", twtCapabilities.get());
7221             // Assume device is a TWT requester
7222             assumeTrue(twtCapabilities.get().getBoolean(
7223                     WifiManager.TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER));
7224             assertTrue(twtCapabilities.get().getInt(
7225                     WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS) >= 0);
7226             assertTrue(twtCapabilities.get().getInt(
7227                     WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS) >= 0);
7228             assertTrue(twtCapabilities.get().getLong(
7229                     WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS) >= 0);
7230             assertTrue(twtCapabilities.get().getLong(
7231                     WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS) >= 0);
7232 
7233             // Connect to an available TWT responder network
7234             List<WifiConfiguration> savedNetworks = sWifiManager.getConfiguredNetworks();
7235             WifiConfiguration twtNetwork = TestHelper.findFirstAvailableSavedNetwork(sWifiManager,
7236                     savedNetworks, TestHelper.AP_CAPABILITY_BIT_TWT_RESPONDER);
7237             // TODO: Make it an assert once the TWT setup is available for CTS test
7238             assumeTrue("Unable to locate TWT capable networks in range.\n", twtNetwork != null);
7239             sWifiManager.disconnect();
7240             waitForDisconnection();
7241             sWifiManager.connect(twtNetwork.networkId, actionListener);
7242             waitForConnection();
7243 
7244             // Get the first link id, if the connection is multi-link
7245             List<MloLink> mloLinks = sWifiManager.getConnectionInfo().getAssociatedMloLinks();
7246             int linkId = MloLink.INVALID_MLO_LINK_ID;
7247             if (!mloLinks.isEmpty()) {
7248                 linkId = mloLinks.getFirst().getLinkId();
7249             }
7250 
7251             // Build and validate twtRequest
7252             int minWakeDuration = twtCapabilities.get().getInt(
7253                     WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS);
7254             int maxWakeDuration = twtCapabilities.get().getInt(
7255                     WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS);
7256             long minWakeInterval = twtCapabilities.get().getLong(
7257                     WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS);
7258             long maxWakeInterval = twtCapabilities.get().getLong(
7259                     WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS);
7260             TwtRequest.Builder builder = new TwtRequest.Builder(minWakeDuration, maxWakeDuration,
7261                     minWakeInterval, maxWakeInterval);
7262             if (linkId != MloLink.INVALID_MLO_LINK_ID) {
7263                 builder.setLinkId(linkId);
7264             }
7265             TwtRequest twtRequest = builder.build();
7266             assertEquals(twtRequest.getMinWakeDurationMicros(), minWakeDuration);
7267             assertEquals(twtRequest.getMaxWakeDurationMicros(), maxWakeDuration);
7268             assertEquals(twtRequest.getMinWakeIntervalMicros(), minWakeInterval);
7269             assertEquals(twtRequest.getMaxWakeIntervalMicros(), maxWakeInterval);
7270             assertEquals(twtRequest.getLinkId(), linkId);
7271 
7272             // Verify TWT session setup
7273             sWifiManager.setupTwtSession(twtRequest, mExecutor, testTwtSessionCallback);
7274             synchronized (mLock) {
7275                 now = System.currentTimeMillis();
7276                 deadline = now + TEST_WAIT_DURATION_MS;
7277                 while (testTwtSessionCallback.mTwtSession.get() == null && now < deadline) {
7278                     mLock.wait(deadline - now);
7279                     now = System.currentTimeMillis();
7280                 }
7281             }
7282             assertNotNull("setupTwtSession() timed out !",
7283                     testTwtSessionCallback.mTwtSession.get());
7284             assertTrue(testTwtSessionCallback.mTwtSession.get().getWakeDurationMicros() > 0);
7285             assertTrue(testTwtSessionCallback.mTwtSession.get().getWakeIntervalMicros() > 0);
7286             assertTrue(testTwtSessionCallback.mTwtSession.get().getMloLinkId() == linkId);
7287 
7288             // Verify TWT session get stats
7289             testTwtSessionCallback.mTwtSession.get().getStats(mExecutor, twtStatsCallback);
7290             synchronized (mLock) {
7291                 now = System.currentTimeMillis();
7292                 deadline = now + TEST_WAIT_DURATION_MS;
7293                 while (twtStats.get() == null && now < deadline) {
7294                     mLock.wait(deadline - now);
7295                     now = System.currentTimeMillis();
7296                 }
7297             }
7298             assertNotNull("TwtSession#getStats() timed out !", twtStats.get());
7299             assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT)
7300                     >= 0);
7301             assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT)
7302                     >= 0);
7303             assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE)
7304                     >= 0);
7305             assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE)
7306                     >= 0);
7307             assertTrue(
7308                     twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS)
7309                             >= 0);
7310             assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_EOSP_COUNT) >= 0);
7311 
7312             // Verify TWT session teardown
7313             testTwtSessionCallback.mTwtSession.get().teardown();
7314             synchronized (mLock) {
7315                 now = System.currentTimeMillis();
7316                 deadline = now + TEST_WAIT_DURATION_MS;
7317                 while (testTwtSessionCallback.mTwtTeardownReasonCode.get() == -1
7318                         && now < deadline) {
7319                     mLock.wait(deadline - now);
7320                     now = System.currentTimeMillis();
7321                 }
7322             }
7323             assertNotEquals("TwtSession#teardown() timed out !", -1,
7324                     testTwtSessionCallback.mTwtTeardownReasonCode.get());
7325             assertTrue(testTwtSessionCallback.mTwtTeardownReasonCode.get()
7326                     == TwtSessionCallback.TWT_REASON_CODE_LOCALLY_REQUESTED);
7327         } finally {
7328             uiAutomation.dropShellPermissionIdentity();
7329         }
7330     }
7331 
7332     /**
7333      * Tests {@link WifiManager#isD2dSupportedWhenInfraStaDisabled()},
7334      * {@link WifiManager#setD2dAllowedWhenInfraStaDisabled()} and
7335      * {@link WifiManager#queryD2dAllowedWhenInfraStaDisabled()}.
7336      */
7337     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
7338     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
7339     @Test
testD2dAllowedWhenInfraStaDisabled()7340     public void testD2dAllowedWhenInfraStaDisabled() throws Exception {
7341         if (!sWifiManager.isD2dSupportedWhenInfraStaDisabled()) {
7342             // skip the test if feature is not supported.
7343             return;
7344         }
7345         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
7346         Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false);
7347         boolean currentD2dAllowed = false;
7348         boolean isRestoreRequired = false;
7349         long now, deadline;
7350         try {
7351             uiAutomation.adoptShellPermissionIdentity();
7352             Mutable<Boolean> isD2dAllowed = new Mutable<Boolean>(false);
7353             sWifiManager.queryD2dAllowedWhenInfraStaDisabled(mExecutor,
7354                     new Consumer<Boolean>() {
7355                     @Override
7356                     public void accept(Boolean value) {
7357                         synchronized (mLock) {
7358                             isD2dAllowed.value = value;
7359                             isQuerySucceeded.value = true;
7360                             mLock.notify();
7361                         }
7362                     }
7363                 });
7364             synchronized (mLock) {
7365                 now = System.currentTimeMillis();
7366                 deadline = now + TEST_WAIT_DURATION_MS;
7367                 while (!isQuerySucceeded.value && now < deadline) {
7368                     mLock.wait(deadline - now);
7369                     now = System.currentTimeMillis();
7370                 }
7371             }
7372             assertTrue("d2d allowed query fail", isQuerySucceeded.value);
7373             // Reset for next query
7374             isQuerySucceeded.value = false;
7375             currentD2dAllowed = isD2dAllowed.value;
7376             isRestoreRequired = true;
7377             sWifiManager.setD2dAllowedWhenInfraStaDisabled(!currentD2dAllowed);
7378             sWifiManager.queryD2dAllowedWhenInfraStaDisabled(mExecutor,
7379                     new Consumer<Boolean>() {
7380                     @Override
7381                     public void accept(Boolean value) {
7382                         synchronized (mLock) {
7383                             isD2dAllowed.value = value;
7384                             isQuerySucceeded.value = true;
7385                             mLock.notify();
7386                         }
7387                     }
7388                 });
7389             synchronized (mLock) {
7390                 now = System.currentTimeMillis();
7391                 deadline = now + TEST_WAIT_DURATION_MS;
7392                 while (!isQuerySucceeded.value && now < deadline) {
7393                     mLock.wait(deadline - now);
7394                     now = System.currentTimeMillis();
7395                 }
7396             }
7397             assertEquals("set/query d2d allowed should match",
7398                     isD2dAllowed.value, !currentD2dAllowed);
7399         } finally {
7400             if (isRestoreRequired) {
7401                 sWifiManager.setD2dAllowedWhenInfraStaDisabled(currentD2dAllowed);
7402             }
7403             uiAutomation.dropShellPermissionIdentity();
7404         }
7405     }
7406 
7407     /**
7408      * Tests {@link WifiManager#getBssidBlocklist(List, Executor, Consumer)}
7409      */
7410     @RequiresFlagsEnabled(Flags.FLAG_GET_BSSID_BLOCKLIST_API)
7411     @Test
7412     @ApiTest(apis = {"android.net.wifi.WifiManager#getBssidBlocklist"})
testGetBssidBlocklist()7413     public void testGetBssidBlocklist() throws Exception {
7414         Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false);
7415         Mutable<Boolean> isResultNonNull = new Mutable<Boolean>(false);
7416         long now, deadline;
7417         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
7418         try {
7419             uiAutomation.adoptShellPermissionIdentity();
7420             sWifiManager.getBssidBlocklist(Collections.EMPTY_LIST, mExecutor,
7421                     new Consumer<List<MacAddress>>() {
7422                         @Override
7423                         public void accept(List<MacAddress> value) {
7424                             synchronized (mLock) {
7425                                 isQuerySucceeded.value = true;
7426                                 if (value != null) {
7427                                     isResultNonNull.value = true;
7428                                 }
7429                                 mLock.notify();
7430                             }
7431                         }
7432                     });
7433             synchronized (mLock) {
7434                 now = System.currentTimeMillis();
7435                 deadline = now + TEST_WAIT_DURATION_MS;
7436                 while (!isQuerySucceeded.value && now < deadline) {
7437                     mLock.wait(deadline - now);
7438                     now = System.currentTimeMillis();
7439                 }
7440             }
7441             assertTrue("getBssidBlocklist fail", isQuerySucceeded.value);
7442             assertTrue("getBssidBlocklist returned null list", isResultNonNull.value);
7443         } finally {
7444             uiAutomation.dropShellPermissionIdentity();
7445         }
7446     }
7447 
7448     /**
7449      * Tests {@link WifiManager#retrieveWifiBackupData()},
7450      * {@link WifiManager#restoreWifiBackupData()}.
7451      */
7452     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
7453     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM,
7454             codeName = "VanillaIceCream")
7455     @Test
testWifiBackupRestore()7456     public void testWifiBackupRestore() throws Exception {
7457         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
7458         Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false);
7459         Mutable<byte[]> backupWifiData = new Mutable<byte[]>();
7460         long now, deadline;
7461         try {
7462             uiAutomation.adoptShellPermissionIdentity();
7463             sWifiManager.retrieveWifiBackupData(mExecutor,
7464                     new Consumer<byte[]>() {
7465                     @Override
7466                     public void accept(byte[] value) {
7467                         synchronized (mLock) {
7468                             isQuerySucceeded.value = true;
7469                             backupWifiData.value = value;
7470                             mLock.notify();
7471                         }
7472                     }
7473                 });
7474             // Test no crash when calling backup/restore api
7475             synchronized (mLock) {
7476                 now = System.currentTimeMillis();
7477                 deadline = now + TEST_WAIT_DURATION_MS;
7478                 while (!isQuerySucceeded.value && now < deadline) {
7479                     mLock.wait(deadline - now);
7480                     now = System.currentTimeMillis();
7481                 }
7482             }
7483             assertTrue("retrieve Wi-Fi backup data fail", isQuerySucceeded.value);
7484             sWifiManager.restoreWifiBackupData(backupWifiData.value);
7485         } finally {
7486             uiAutomation.dropShellPermissionIdentity();
7487         }
7488     }
7489 }
7490