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