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