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