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