| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net.wifi.cts; |
| |
| import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; |
| import static android.net.NetworkCapabilities.TRANSPORT_WIFI; |
| import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; |
| |
| import static com.google.common.truth.Truth.assertWithMessage; |
| |
| import static org.junit.Assert.assertNotEquals; |
| |
| import android.app.UiAutomation; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.net.ConnectivityManager; |
| import android.net.LinkProperties; |
| import android.net.MacAddress; |
| import android.net.Network; |
| import android.net.NetworkCapabilities; |
| import android.net.NetworkInfo; |
| import android.net.NetworkRequest; |
| import android.net.TetheringManager; |
| import android.net.Uri; |
| import android.net.util.MacAddressUtils; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.SoftApCapability; |
| import android.net.wifi.SoftApConfiguration; |
| import android.net.wifi.SoftApInfo; |
| import android.net.wifi.WifiClient; |
| import android.net.wifi.WifiConfiguration; |
| import android.net.wifi.WifiInfo; |
| import android.net.wifi.WifiManager; |
| import android.net.wifi.WifiManager.WifiLock; |
| import android.net.wifi.WifiNetworkConnectionStatistics; |
| import android.net.wifi.WifiNetworkSuggestion; |
| import android.net.wifi.hotspot2.ConfigParser; |
| import android.net.wifi.hotspot2.OsuProvider; |
| import android.net.wifi.hotspot2.PasspointConfiguration; |
| import android.net.wifi.hotspot2.ProvisioningCallback; |
| import android.net.wifi.hotspot2.pps.Credential; |
| import android.net.wifi.hotspot2.pps.HomeSp; |
| import android.os.Handler; |
| import android.os.HandlerExecutor; |
| import android.os.HandlerThread; |
| import android.os.Process; |
| import android.os.SystemClock; |
| import android.os.UserHandle; |
| import android.platform.test.annotations.AppModeFull; |
| import android.provider.Settings; |
| import android.support.test.uiautomator.UiDevice; |
| import android.telephony.TelephonyManager; |
| import android.test.AndroidTestCase; |
| import android.text.TextUtils; |
| import android.util.ArraySet; |
| import android.util.Log; |
| |
| import androidx.test.platform.app.InstrumentationRegistry; |
| |
| import com.android.compatibility.common.util.PollingCheck; |
| import com.android.compatibility.common.util.ShellIdentityUtils; |
| import com.android.compatibility.common.util.SystemUtil; |
| import com.android.compatibility.common.util.ThrowingRunnable; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.lang.reflect.Constructor; |
| import java.net.HttpURLConnection; |
| import java.net.InetAddress; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentLinkedQueue; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.Executor; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.TimeUnit; |
| import java.util.stream.Collectors; |
| |
| @AppModeFull(reason = "Cannot get WifiManager in instant app mode") |
| public class WifiManagerTest extends WifiJUnit3TestBase { |
| private static class MySync { |
| int expectedState = STATE_NULL; |
| } |
| |
| private WifiManager mWifiManager; |
| private ConnectivityManager mConnectivityManager; |
| private TetheringManager mTetheringManager; |
| private WifiLock mWifiLock; |
| private static MySync mMySync; |
| private List<ScanResult> mScanResults = null; |
| private NetworkInfo mNetworkInfo; |
| private final Object mLock = new Object(); |
| private UiDevice mUiDevice; |
| private boolean mWasVerboseLoggingEnabled; |
| private boolean mWasScanThrottleEnabled; |
| private SoftApConfiguration mOriginalSoftApConfig = null; |
| |
| // Please refer to WifiManager |
| private static final int MIN_RSSI = -100; |
| private static final int MAX_RSSI = -55; |
| |
| private static final int STATE_NULL = 0; |
| private static final int STATE_WIFI_CHANGING = 1; |
| private static final int STATE_WIFI_ENABLED = 2; |
| private static final int STATE_WIFI_DISABLED = 3; |
| private static final int STATE_SCANNING = 4; |
| private static final int STATE_SCAN_DONE = 5; |
| |
| private static final String TAG = "WifiManagerTest"; |
| private static final String SSID1 = "\"WifiManagerTest\""; |
| // A full single scan duration is about 6-7 seconds if country code is set |
| // to US. If country code is set to world mode (00), we would expect a scan |
| // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here. |
| private static final int SCAN_TEST_WAIT_DURATION_MS = 9000; |
| private static final int TEST_WAIT_DURATION_MS = 10_000; |
| private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000; |
| private static final int WAIT_MSEC = 60; |
| private static final int DURATION_SCREEN_TOGGLE = 2000; |
| private static final int DURATION_SETTINGS_TOGGLE = 1_000; |
| private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000; |
| private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; |
| private static final int WIFI_SCAN_TEST_ITERATIONS = 5; |
| |
| private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50; |
| |
| private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; |
| private static final String MANAGED_PROVISIONING_PACKAGE_NAME |
| = "com.android.managedprovisioning"; |
| |
| private static final String TEST_SSID_UNQUOTED = "testSsid1"; |
| private static final String TEST_IP_ADDRESS = "192.168.5.5"; |
| private static final String TEST_MAC_ADDRESS = "aa:bb:cc:dd:ee:ff"; |
| private static final MacAddress TEST_MAC = MacAddress.fromString(TEST_MAC_ADDRESS); |
| private static final String TEST_PASSPHRASE = "passphrase"; |
| private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT = |
| "assets/ValidPasspointProfile.base64"; |
| private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config"; |
| private static final String TEST_PSK_CAP = "[RSN-PSK-CCMP]"; |
| private static final String TEST_BSSID = "00:01:02:03:04:05"; |
| |
| private IntentFilter mIntentFilter; |
| private final BroadcastReceiver mReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| final String action = intent.getAction(); |
| if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { |
| |
| synchronized (mMySync) { |
| if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { |
| mScanResults = mWifiManager.getScanResults(); |
| } else { |
| mScanResults = null; |
| } |
| mMySync.expectedState = STATE_SCAN_DONE; |
| mMySync.notifyAll(); |
| } |
| } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { |
| int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, |
| WifiManager.WIFI_STATE_UNKNOWN); |
| synchronized (mMySync) { |
| if (newState == WifiManager.WIFI_STATE_ENABLED) { |
| Log.d(TAG, "*** New WiFi state is ENABLED ***"); |
| mMySync.expectedState = STATE_WIFI_ENABLED; |
| mMySync.notifyAll(); |
| } else if (newState == WifiManager.WIFI_STATE_DISABLED) { |
| Log.d(TAG, "*** New WiFi state is DISABLED ***"); |
| mMySync.expectedState = STATE_WIFI_DISABLED; |
| mMySync.notifyAll(); |
| } |
| } |
| } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { |
| synchronized (mMySync) { |
| mNetworkInfo = |
| (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); |
| if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) |
| mMySync.notifyAll(); |
| } |
| } |
| } |
| }; |
| // Initialize with an invalid status value (0) |
| private int mProvisioningStatus = 0; |
| // Initialize with an invalid status value (0) |
| private int mProvisioningFailureStatus = 0; |
| private boolean mProvisioningComplete = false; |
| private ProvisioningCallback mProvisioningCallback = new ProvisioningCallback() { |
| @Override |
| public void onProvisioningFailure(int status) { |
| synchronized (mLock) { |
| mProvisioningFailureStatus = status; |
| mLock.notify(); |
| } |
| } |
| |
| @Override |
| public void onProvisioningStatus(int status) { |
| synchronized (mLock) { |
| mProvisioningStatus = status; |
| mLock.notify(); |
| } |
| } |
| |
| @Override |
| public void onProvisioningComplete() { |
| mProvisioningComplete = true; |
| } |
| }; |
| private static final String TEST_SSID = "TEST SSID"; |
| private static final String TEST_FRIENDLY_NAME = "Friendly Name"; |
| private static final Map<String, String> TEST_FRIENDLY_NAMES = |
| new HashMap<String, String>() { |
| { |
| put("en", TEST_FRIENDLY_NAME); |
| put("kr", TEST_FRIENDLY_NAME + 2); |
| put("jp", TEST_FRIENDLY_NAME + 3); |
| } |
| }; |
| private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service"; |
| private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com"); |
| private static final String TEST_NAI = "test.access.com"; |
| private static final List<Integer> TEST_METHOD_LIST = |
| Arrays.asList(1 /* METHOD_SOAP_XML_SPP */); |
| private final HandlerThread mHandlerThread = new HandlerThread("WifiManagerTest"); |
| protected final Executor mExecutor; |
| { |
| mHandlerThread.start(); |
| mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mMySync = new MySync(); |
| mIntentFilter = new IntentFilter(); |
| mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); |
| mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); |
| mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); |
| mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); |
| mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); |
| mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); |
| mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); |
| mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); |
| |
| mContext.registerReceiver(mReceiver, mIntentFilter); |
| mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); |
| mConnectivityManager = getContext().getSystemService(ConnectivityManager.class); |
| mTetheringManager = getContext().getSystemService(TetheringManager.class); |
| assertNotNull(mWifiManager); |
| assertNotNull(mTetheringManager); |
| |
| // turn on verbose logging for tests |
| mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.isVerboseLoggingEnabled()); |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.setVerboseLoggingEnabled(true)); |
| // Disable scan throttling for tests. |
| mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.isScanThrottleEnabled()); |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.setScanThrottleEnabled(false)); |
| |
| mWifiLock = mWifiManager.createWifiLock(TAG); |
| mWifiLock.acquire(); |
| // enable Wifi |
| if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); |
| PollingCheck.check("Wifi not enabled", TEST_WAIT_DURATION_MS, |
| () -> mWifiManager.isWifiEnabled()); |
| |
| mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); |
| turnScreenOnNoDelay(); |
| |
| synchronized (mMySync) { |
| mMySync.expectedState = STATE_NULL; |
| } |
| |
| List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getConfiguredNetworks); |
| assertFalse("Need at least one saved network", savedNetworks.isEmpty()); |
| |
| // Get original config for restore |
| mOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getSoftApConfiguration); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| super.tearDown(); |
| return; |
| } |
| if (!mWifiManager.isWifiEnabled()) |
| setWifiEnabled(true); |
| mWifiLock.release(); |
| mContext.unregisterReceiver(mReceiver); |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); |
| // restore original softap config |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.setSoftApConfiguration(mOriginalSoftApConfig)); |
| Thread.sleep(TEST_WAIT_DURATION_MS); |
| super.tearDown(); |
| } |
| |
| private void setWifiEnabled(boolean enable) throws Exception { |
| synchronized (mMySync) { |
| if (mWifiManager.isWifiEnabled() != enable) { |
| // the new state is different, we expect it to change |
| mMySync.expectedState = STATE_WIFI_CHANGING; |
| } else { |
| mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); |
| } |
| // now trigger the change using shell commands. |
| SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); |
| waitForExpectedWifiState(enable); |
| } |
| } |
| |
| private void waitForExpectedWifiState(boolean enabled) throws InterruptedException { |
| synchronized (mMySync) { |
| long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS; |
| int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); |
| while (System.currentTimeMillis() < timeout |
| && mMySync.expectedState != expected) { |
| mMySync.wait(WAIT_MSEC); |
| } |
| } |
| } |
| |
| // Get the current scan status from sticky broadcast. |
| private boolean isScanCurrentlyAvailable() { |
| IntentFilter intentFilter = new IntentFilter(); |
| intentFilter.addAction(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED); |
| Intent intent = mContext.registerReceiver(null, intentFilter); |
| assertNotNull(intent); |
| if (intent.getAction().equals(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED)) { |
| return intent.getBooleanExtra(WifiManager.EXTRA_SCAN_AVAILABLE, false); |
| } |
| return false; |
| } |
| |
| private void startScan() throws Exception { |
| synchronized (mMySync) { |
| mMySync.expectedState = STATE_SCANNING; |
| mScanResults = null; |
| assertTrue(mWifiManager.startScan()); |
| long timeout = System.currentTimeMillis() + SCAN_TEST_WAIT_DURATION_MS; |
| while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANNING) |
| mMySync.wait(WAIT_MSEC); |
| } |
| } |
| |
| private void waitForNetworkInfoState(NetworkInfo.State state, int timeoutMillis) |
| throws Exception { |
| synchronized (mMySync) { |
| if (mNetworkInfo.getState() == state) return; |
| long timeout = System.currentTimeMillis() + timeoutMillis; |
| while (System.currentTimeMillis() < timeout |
| && mNetworkInfo.getState() != state) |
| mMySync.wait(WAIT_MSEC); |
| assertEquals(state, mNetworkInfo.getState()); |
| } |
| } |
| |
| private void waitForConnection() throws Exception { |
| waitForNetworkInfoState(NetworkInfo.State.CONNECTED, WIFI_CONNECT_TIMEOUT_MILLIS); |
| } |
| |
| private void waitForDisconnection() throws Exception { |
| waitForNetworkInfoState(NetworkInfo.State.DISCONNECTED, TEST_WAIT_DURATION_MS); |
| } |
| |
| private void ensureNotNetworkInfoState(NetworkInfo.State state) throws Exception { |
| synchronized (mMySync) { |
| long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS + WAIT_MSEC; |
| while (System.currentTimeMillis() < timeout) { |
| assertNotEquals(state, mNetworkInfo.getState()); |
| mMySync.wait(WAIT_MSEC); |
| } |
| } |
| } |
| |
| private void ensureNotConnected() throws Exception { |
| ensureNotNetworkInfoState(NetworkInfo.State.CONNECTED); |
| } |
| |
| private void ensureNotDisconnected() throws Exception { |
| ensureNotNetworkInfoState(NetworkInfo.State.DISCONNECTED); |
| } |
| |
| private boolean existSSID(String ssid) { |
| for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { |
| if (w.SSID.equals(ssid)) |
| return true; |
| } |
| return false; |
| } |
| |
| private int findConfiguredNetworks(String SSID, List<WifiConfiguration> networks) { |
| for (final WifiConfiguration w : networks) { |
| if (w.SSID.equals(SSID)) |
| return networks.indexOf(w); |
| } |
| return -1; |
| } |
| |
| /** |
| * Test creation of WifiManager Lock. |
| */ |
| public void testWifiManagerLock() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final String TAG = "Test"; |
| assertNotNull(mWifiManager.createWifiLock(TAG)); |
| assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); |
| } |
| |
| /** |
| * Test wifi scanning when Wifi is off and location scanning is turned on. |
| */ |
| public void testWifiManagerScanWhenWifiOffLocationTurnedOn() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| if (!hasLocationFeature()) { |
| Log.d(TAG, "Skipping test as location is not supported"); |
| return; |
| } |
| if (!isLocationEnabled()) { |
| fail("Please enable location for this test - since Marshmallow WiFi scan results are" |
| + " empty when location is disabled!"); |
| } |
| runWithScanningEnabled(() -> { |
| setWifiEnabled(false); |
| Thread.sleep(TEST_WAIT_DURATION_MS); |
| startScan(); |
| if (mWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) { |
| // Make sure at least one AP is found. |
| assertNotNull("mScanResult should not be null!", mScanResults); |
| assertFalse("empty scan results!", mScanResults.isEmpty()); |
| } else { |
| // Make sure no scan results are available. |
| assertNull("mScanResult should be null!", mScanResults); |
| } |
| final String TAG = "Test"; |
| assertNotNull(mWifiManager.createWifiLock(TAG)); |
| assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); |
| }); |
| } |
| |
| /** |
| * test point of wifiManager properties: |
| * 1.enable properties |
| * 2.DhcpInfo properties |
| * 3.wifi state |
| * 4.ConnectionInfo |
| */ |
| public void testWifiManagerProperties() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| setWifiEnabled(true); |
| assertTrue(mWifiManager.isWifiEnabled()); |
| assertNotNull(mWifiManager.getDhcpInfo()); |
| assertEquals(WifiManager.WIFI_STATE_ENABLED, mWifiManager.getWifiState()); |
| mWifiManager.getConnectionInfo(); |
| setWifiEnabled(false); |
| assertFalse(mWifiManager.isWifiEnabled()); |
| } |
| |
| /** |
| * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with |
| * {@link SystemClock#elapsedRealtime()} on device.<p> |
| * To run this test in cts-tradefed: |
| * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp |
| */ |
| public void testWifiScanTimestamp() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| Log.d(TAG, "Skipping test as WiFi is not supported"); |
| return; |
| } |
| if (!hasLocationFeature()) { |
| Log.d(TAG, "Skipping test as location is not supported"); |
| return; |
| } |
| if (!isLocationEnabled()) { |
| fail("Please enable location for this test - since Marshmallow WiFi scan results are" |
| + " empty when location is disabled!"); |
| } |
| if (!mWifiManager.isWifiEnabled()) { |
| setWifiEnabled(true); |
| } |
| // Scan multiple times to make sure scan timestamps increase with device timestamp. |
| for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) { |
| startScan(); |
| // Make sure at least one AP is found. |
| assertTrue("mScanResult should not be null. This may be due to a scan timeout", |
| mScanResults != null); |
| assertFalse("empty scan results!", mScanResults.isEmpty()); |
| long nowMillis = SystemClock.elapsedRealtime(); |
| // Keep track of how many APs are fresh in one scan. |
| int numFreshAps = 0; |
| for (ScanResult result : mScanResults) { |
| long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp); |
| if (Math.abs(nowMillis - scanTimeMillis) < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) { |
| numFreshAps++; |
| } |
| } |
| // At least half of the APs in the scan should be fresh. |
| int numTotalAps = mScanResults.size(); |
| String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: " |
| + numFreshAps; |
| assertTrue(msg, numFreshAps * 2 >= mScanResults.size()); |
| if (i < WIFI_SCAN_TEST_ITERATIONS - 1) { |
| // Wait before running next iteration. |
| Thread.sleep(WIFI_SCAN_TEST_INTERVAL_MILLIS); |
| } |
| } |
| } |
| |
| // Return true if location is enabled. |
| private boolean isLocationEnabled() { |
| return Settings.Secure.getInt(getContext().getContentResolver(), |
| Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) != |
| Settings.Secure.LOCATION_MODE_OFF; |
| } |
| |
| // Returns true if the device has location feature. |
| private boolean hasLocationFeature() { |
| return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); |
| } |
| |
| private boolean hasAutomotiveFeature() { |
| return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); |
| } |
| |
| public void testSignal() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final int numLevels = 9; |
| int expectLevel = 0; |
| assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels)); |
| assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels)); |
| expectLevel = 4; |
| assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2, |
| numLevels)); |
| int rssiA = 4; |
| int rssiB = 5; |
| assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0); |
| rssiB = 4; |
| assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0); |
| rssiA = 5; |
| rssiB = 4; |
| assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0); |
| } |
| |
| /** |
| * Test that {@link WifiManager#calculateSignalLevel(int)} returns a value in the range |
| * [0, {@link WifiManager#getMaxSignalLevel()}], and its value is monotonically increasing as |
| * the RSSI increases. |
| */ |
| public void testCalculateSignalLevel() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| int maxSignalLevel = mWifiManager.getMaxSignalLevel(); |
| |
| int prevSignalLevel = 0; |
| for (int rssi = -150; rssi <= 50; rssi++) { |
| int signalLevel = mWifiManager.calculateSignalLevel(rssi); |
| |
| // between [0, maxSignalLevel] |
| assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(0); |
| assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtMost(maxSignalLevel); |
| |
| // calculateSignalLevel(rssi) <= calculateSignalLevel(rssi + 1) |
| assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(prevSignalLevel); |
| prevSignalLevel = signalLevel; |
| } |
| } |
| |
| public class TestSoftApCallback implements WifiManager.SoftApCallback { |
| Object softApLock; |
| int currentState; |
| int currentFailureReason; |
| List<WifiClient> currentClientList; |
| SoftApInfo currentSoftApInfo; |
| SoftApCapability currentSoftApCapability; |
| MacAddress lastBlockedClientMacAddress; |
| int lastBlockedClientReason; |
| boolean onStateChangedCalled = false; |
| boolean onSoftApCapabilityChangedCalled = false; |
| boolean onConnectedClientCalled = false; |
| boolean onBlockedClientConnectingCalled = false; |
| int onSoftapInfoChangedCalledCount = 0; |
| |
| TestSoftApCallback(Object lock) { |
| softApLock = lock; |
| } |
| |
| public boolean getOnStateChangedCalled() { |
| synchronized(softApLock) { |
| return onStateChangedCalled; |
| } |
| } |
| |
| public int getOnSoftapInfoChangedCalledCount() { |
| synchronized(softApLock) { |
| return onSoftapInfoChangedCalledCount; |
| } |
| } |
| |
| public boolean getOnSoftApCapabilityChangedCalled() { |
| synchronized(softApLock) { |
| return onSoftApCapabilityChangedCalled; |
| } |
| } |
| |
| public boolean getOnConnectedClientCalled() { |
| synchronized(softApLock) { |
| return onConnectedClientCalled; |
| } |
| } |
| |
| public boolean getOnBlockedClientConnectingCalled() { |
| synchronized(softApLock) { |
| return onBlockedClientConnectingCalled; |
| } |
| } |
| |
| public int getCurrentState() { |
| synchronized(softApLock) { |
| return currentState; |
| } |
| } |
| |
| public int getCurrentStateFailureReason() { |
| synchronized(softApLock) { |
| return currentFailureReason; |
| } |
| } |
| |
| public List<WifiClient> getCurrentClientList() { |
| synchronized(softApLock) { |
| return currentClientList; |
| } |
| } |
| |
| public SoftApInfo getCurrentSoftApInfo() { |
| synchronized(softApLock) { |
| return currentSoftApInfo; |
| } |
| } |
| |
| public SoftApCapability getCurrentSoftApCapability() { |
| synchronized(softApLock) { |
| return currentSoftApCapability; |
| } |
| } |
| |
| public MacAddress getLastBlockedClientMacAddress() { |
| synchronized(softApLock) { |
| return lastBlockedClientMacAddress; |
| } |
| } |
| |
| public int getLastBlockedClientReason() { |
| synchronized(softApLock) { |
| return lastBlockedClientReason; |
| } |
| } |
| |
| @Override |
| public void onStateChanged(int state, int failureReason) { |
| synchronized(softApLock) { |
| currentState = state; |
| currentFailureReason = failureReason; |
| onStateChangedCalled = true; |
| } |
| } |
| |
| @Override |
| public void onConnectedClientsChanged(List<WifiClient> clients) { |
| synchronized(softApLock) { |
| currentClientList = new ArrayList<>(clients); |
| onConnectedClientCalled = true; |
| } |
| } |
| |
| @Override |
| public void onInfoChanged(SoftApInfo softApInfo) { |
| synchronized(softApLock) { |
| currentSoftApInfo = softApInfo; |
| onSoftapInfoChangedCalledCount++; |
| } |
| } |
| |
| @Override |
| public void onCapabilityChanged(SoftApCapability softApCapability) { |
| synchronized(softApLock) { |
| currentSoftApCapability = softApCapability; |
| onSoftApCapabilityChangedCalled = true; |
| } |
| } |
| |
| @Override |
| public void onBlockedClientConnecting(WifiClient client, int blockedReason) { |
| synchronized(softApLock) { |
| lastBlockedClientMacAddress = client.getMacAddress(); |
| lastBlockedClientReason = blockedReason; |
| onBlockedClientConnectingCalled = true; |
| } |
| } |
| } |
| |
| private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback { |
| Object hotspotLock; |
| WifiManager.LocalOnlyHotspotReservation reservation = null; |
| boolean onStartedCalled = false; |
| boolean onStoppedCalled = false; |
| boolean onFailedCalled = false; |
| int failureReason = -1; |
| |
| TestLocalOnlyHotspotCallback(Object lock) { |
| hotspotLock = lock; |
| } |
| |
| @Override |
| public void onStarted(WifiManager.LocalOnlyHotspotReservation r) { |
| synchronized (hotspotLock) { |
| reservation = r; |
| onStartedCalled = true; |
| hotspotLock.notify(); |
| } |
| } |
| |
| @Override |
| public void onStopped() { |
| synchronized (hotspotLock) { |
| onStoppedCalled = true; |
| hotspotLock.notify(); |
| } |
| } |
| |
| @Override |
| public void onFailed(int reason) { |
| synchronized (hotspotLock) { |
| onFailedCalled = true; |
| failureReason = reason; |
| hotspotLock.notify(); |
| } |
| } |
| } |
| |
| private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() { |
| // Location mode must be enabled for this test |
| if (!isLocationEnabled()) { |
| fail("Please enable location for this test"); |
| } |
| |
| TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); |
| synchronized (mLock) { |
| try { |
| mWifiManager.startLocalOnlyHotspot(callback, null); |
| // now wait for callback |
| mLock.wait(TEST_WAIT_DURATION_MS); |
| } catch (InterruptedException e) { |
| } |
| // check if we got the callback |
| assertTrue(callback.onStartedCalled); |
| |
| SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); |
| assertNotNull(softApConfig); |
| int securityType = softApConfig.getSecurityType(); |
| if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN |
| || securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) { |
| // TODO: b/165504232, add WPA3_SAE_TRANSITION assert check |
| assertNotNull(softApConfig.toWifiConfiguration()); |
| } else if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE) { |
| assertNull(softApConfig.toWifiConfiguration()); |
| } |
| if (!hasAutomotiveFeature()) { |
| assertEquals( |
| SoftApConfiguration.BAND_2GHZ, |
| callback.reservation.getSoftApConfiguration().getBand()); |
| } |
| assertFalse(callback.onFailedCalled); |
| assertFalse(callback.onStoppedCalled); |
| } |
| return callback; |
| } |
| |
| private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) { |
| synchronized (mMySync) { |
| // we are expecting a new state |
| mMySync.expectedState = STATE_WIFI_CHANGING; |
| |
| // now shut down LocalOnlyHotspot |
| callback.reservation.close(); |
| |
| try { |
| waitForExpectedWifiState(wifiEnabled); |
| } catch (InterruptedException e) {} |
| } |
| } |
| |
| /** |
| * Verify that calls to startLocalOnlyHotspot succeed with proper permissions. |
| * |
| * Note: Location mode must be enabled for this test. |
| */ |
| public void testStartLocalOnlyHotspotSuccess() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // check that softap mode is supported by the device |
| if (!mWifiManager.isPortableHotspotSupported()) { |
| return; |
| } |
| |
| boolean wifiEnabled = mWifiManager.isWifiEnabled(); |
| |
| TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); |
| |
| // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. |
| // TODO: remove this sleep as soon as b/124330089 is fixed. |
| Log.d(TAG, "Sleeping for 2 seconds"); |
| Thread.sleep(2000); |
| |
| stopLocalOnlyHotspot(callback, wifiEnabled); |
| |
| // wifi should either stay on, or come back on |
| assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); |
| } |
| |
| /** |
| * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK. |
| */ |
| public void testDeprecatedApis() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| setWifiEnabled(true); |
| waitForConnection(); // ensures that there is at-least 1 saved network on the device. |
| |
| WifiConfiguration wifiConfiguration = new WifiConfiguration(); |
| wifiConfiguration.SSID = SSID1; |
| wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); |
| |
| assertEquals(INVALID_NETWORK_ID, |
| mWifiManager.addNetwork(wifiConfiguration)); |
| assertEquals(INVALID_NETWORK_ID, |
| mWifiManager.updateNetwork(wifiConfiguration)); |
| assertFalse(mWifiManager.enableNetwork(0, true)); |
| assertFalse(mWifiManager.disableNetwork(0)); |
| assertFalse(mWifiManager.removeNetwork(0)); |
| assertFalse(mWifiManager.disconnect()); |
| assertFalse(mWifiManager.reconnect()); |
| assertFalse(mWifiManager.reassociate()); |
| assertTrue(mWifiManager.getConfiguredNetworks().isEmpty()); |
| |
| boolean wifiEnabled = mWifiManager.isWifiEnabled(); |
| // now we should fail to toggle wifi state. |
| assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled)); |
| Thread.sleep(TEST_WAIT_DURATION_MS); |
| assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); |
| } |
| |
| /** |
| * Verify that applications can only have one registered LocalOnlyHotspot request at a time. |
| * |
| * Note: Location mode must be enabled for this test. |
| */ |
| public void testStartLocalOnlyHotspotSingleRequestByApps() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // check that softap mode is supported by the device |
| if (!mWifiManager.isPortableHotspotSupported()) { |
| return; |
| } |
| |
| boolean caughtException = false; |
| |
| boolean wifiEnabled = mWifiManager.isWifiEnabled(); |
| |
| TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); |
| |
| // now make a second request - this should fail. |
| TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLock); |
| try { |
| mWifiManager.startLocalOnlyHotspot(callback2, null); |
| } catch (IllegalStateException e) { |
| Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice"); |
| caughtException = true; |
| } |
| if (!caughtException) { |
| // second start did not fail, should clean up the hotspot. |
| |
| // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. |
| // TODO: remove this sleep as soon as b/124330089 is fixed. |
| Log.d(TAG, "Sleeping for 2 seconds"); |
| Thread.sleep(2000); |
| |
| stopLocalOnlyHotspot(callback2, wifiEnabled); |
| } |
| assertTrue(caughtException); |
| |
| // add sleep to avoid calling stopLocalOnlyHotspot before TetherController initialization. |
| // TODO: remove this sleep as soon as b/124330089 is fixed. |
| Log.d(TAG, "Sleeping for 2 seconds"); |
| Thread.sleep(2000); |
| |
| stopLocalOnlyHotspot(callback, wifiEnabled); |
| } |
| |
| private static class TestExecutor implements Executor { |
| private ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>(); |
| |
| @Override |
| public void execute(Runnable task) { |
| tasks.add(task); |
| } |
| |
| private void runAll() { |
| Runnable task = tasks.poll(); |
| while (task != null) { |
| task.run(); |
| task = tasks.poll(); |
| } |
| } |
| } |
| |
| public void testStartLocalOnlyHotspotWithConfigBssid() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // check that softap mode is supported by the device |
| if (!mWifiManager.isPortableHotspotSupported()) { |
| return; |
| } |
| SoftApConfiguration customConfig = new SoftApConfiguration.Builder() |
| .setBssid(TEST_MAC) |
| .setSsid(TEST_SSID_UNQUOTED) |
| .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .build(); |
| TestExecutor executor = new TestExecutor(); |
| TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| |
| boolean wifiEnabled = mWifiManager.isWifiEnabled(); |
| mWifiManager.startLocalOnlyHotspot(customConfig, executor, callback); |
| // now wait for callback |
| Thread.sleep(TEST_WAIT_DURATION_MS); |
| |
| // Verify callback is run on the supplied executor |
| assertFalse(callback.onStartedCalled); |
| executor.runAll(); |
| if (callback.onFailedCalled) { |
| // TODO: b/160752000, customize bssid might not support. |
| // Allow the specific error code. |
| assertEquals(callback.failureReason, |
| WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION); |
| } else { |
| assertTrue(callback.onStartedCalled); |
| |
| assertNotNull(callback.reservation); |
| SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); |
| assertNotNull(softApConfig); |
| assertEquals(TEST_MAC, softApConfig.getBssid()); |
| assertEquals(TEST_SSID_UNQUOTED, softApConfig.getSsid()); |
| assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase()); |
| |
| // clean up |
| stopLocalOnlyHotspot(callback, wifiEnabled); |
| } |
| } finally { |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| public void testStartLocalOnlyHotspotWithNullBssidConfig() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // check that softap mode is supported by the device |
| if (!mWifiManager.isPortableHotspotSupported()) { |
| return; |
| } |
| SoftApConfiguration customConfig = new SoftApConfiguration.Builder() |
| .setSsid(TEST_SSID_UNQUOTED) |
| .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .build(); |
| TestExecutor executor = new TestExecutor(); |
| TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| |
| boolean wifiEnabled = mWifiManager.isWifiEnabled(); |
| mWifiManager.startLocalOnlyHotspot(customConfig, executor, callback); |
| // now wait for callback |
| Thread.sleep(TEST_WAIT_DURATION_MS); |
| |
| // Verify callback is run on the supplied executor |
| assertFalse(callback.onStartedCalled); |
| executor.runAll(); |
| assertTrue(callback.onStartedCalled); |
| |
| assertNotNull(callback.reservation); |
| SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); |
| assertNotNull(softApConfig); |
| assertEquals(TEST_SSID_UNQUOTED, softApConfig.getSsid()); |
| assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase()); |
| |
| // clean up |
| stopLocalOnlyHotspot(callback, wifiEnabled); |
| } finally { |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Read the content of the given resource file into a String. |
| * |
| * @param filename String name of the file |
| * @return String |
| * @throws IOException |
| */ |
| private String loadResourceFile(String filename) throws IOException { |
| InputStream in = getClass().getClassLoader().getResourceAsStream(filename); |
| BufferedReader reader = new BufferedReader(new InputStreamReader(in)); |
| StringBuilder builder = new StringBuilder(); |
| String line; |
| while ((line = reader.readLine()) != null) { |
| builder.append(line).append("\n"); |
| } |
| return builder.toString(); |
| } |
| |
| /** |
| * Verify that changing the mac randomization setting of a Passpoint configuration. |
| */ |
| public void testMacRandomizationSettingPasspoint() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); |
| PasspointConfiguration config = |
| ConfigParser.parsePasspointConfig(TYPE_WIFI_CONFIG, configStr.getBytes()); |
| String fqdn = config.getHomeSp().getFqdn(); |
| String uniqueId = config.getUniqueId(); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| |
| mWifiManager.addOrUpdatePasspointConfiguration(config); |
| PasspointConfiguration passpointConfig = getTargetPasspointConfiguration( |
| mWifiManager.getPasspointConfigurations(), uniqueId); |
| assertNotNull("The installed passpoint profile is missing", passpointConfig); |
| assertTrue("Mac randomization should be enabled for passpoint networks by default.", |
| passpointConfig.isMacRandomizationEnabled()); |
| |
| mWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, false); |
| passpointConfig = getTargetPasspointConfiguration( |
| mWifiManager.getPasspointConfigurations(), uniqueId); |
| assertNotNull("The installed passpoint profile is missing", passpointConfig); |
| assertFalse("Mac randomization should be disabled by the API call.", |
| passpointConfig.isMacRandomizationEnabled()); |
| } finally { |
| // Clean up |
| mWifiManager.removePasspointConfiguration(fqdn); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| /** |
| * Verify that the {@link android.Manifest.permission#NETWORK_STACK} permission is never held by |
| * any package. |
| * <p> |
| * No apps should <em>ever</em> attempt to acquire this permission, since it would give those |
| * apps extremely broad access to connectivity functionality. |
| */ |
| public void testNetworkStackPermission() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final PackageManager pm = getContext().getPackageManager(); |
| |
| final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { |
| android.Manifest.permission.NETWORK_STACK |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| for (PackageInfo pi : holding) { |
| fail("The NETWORK_STACK permission must not be held by " + pi.packageName |
| + " and must be revoked for security reasons"); |
| } |
| } |
| |
| /** |
| * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is |
| * never held by any package. |
| * <p> |
| * Only Settings, SysUi, NetworkStack and shell apps should <em>ever</em> attempt to acquire |
| * this permission, since it would give those apps extremely broad access to connectivity |
| * functionality. The permission is intended to be granted to only those apps with direct user |
| * access and no others. |
| */ |
| public void testNetworkSettingsPermission() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final PackageManager pm = getContext().getPackageManager(); |
| |
| final ArraySet<String> allowedPackages = new ArraySet(); |
| final ArraySet<Integer> allowedUIDs = new ArraySet(); |
| // explicitly add allowed UIDs |
| allowedUIDs.add(Process.SYSTEM_UID); |
| allowedUIDs.add(Process.SHELL_UID); |
| allowedUIDs.add(Process.PHONE_UID); |
| allowedUIDs.add(Process.NETWORK_STACK_UID); |
| allowedUIDs.add(Process.NFC_UID); |
| |
| // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using |
| // this fact to determined allowed package name for sysui. This is a signature permission, |
| // so allow any package with this permission. |
| final List<PackageInfo> sysuiPackages = pm.getPackagesHoldingPermissions(new String[] { |
| android.Manifest.permission.BIND_QUICK_SETTINGS_TILE |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| for (PackageInfo info : sysuiPackages) { |
| allowedPackages.add(info.packageName); |
| } |
| |
| // the captive portal flow also currently holds the NETWORK_SETTINGS permission |
| final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); |
| final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); |
| if (ri != null) { |
| allowedPackages.add(ri.activityInfo.packageName); |
| } |
| |
| final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { |
| android.Manifest.permission.NETWORK_SETTINGS |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| StringBuilder stringBuilder = new StringBuilder(); |
| for (PackageInfo pi : holding) { |
| String packageName = pi.packageName; |
| |
| // this is an explicitly allowed package |
| if (allowedPackages.contains(packageName)) continue; |
| |
| // now check if the packages are from allowed UIDs |
| int uid = -1; |
| try { |
| uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); |
| } catch (PackageManager.NameNotFoundException e) { |
| continue; |
| } |
| if (!allowedUIDs.contains(uid)) { |
| stringBuilder.append("The NETWORK_SETTINGS permission must not be held by " |
| + packageName + ":" + uid + " and must be revoked for security reasons\n"); |
| } |
| } |
| if (stringBuilder.length() > 0) { |
| fail(stringBuilder.toString()); |
| } |
| } |
| |
| /** |
| * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is |
| * only held by the device setup wizard application. |
| * <p> |
| * Only the SetupWizard app should <em>ever</em> attempt to acquire this |
| * permission, since it would give those apps extremely broad access to connectivity |
| * functionality. The permission is intended to be granted to only the device setup wizard. |
| */ |
| public void testNetworkSetupWizardPermission() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final ArraySet<String> allowedPackages = new ArraySet(); |
| |
| final PackageManager pm = getContext().getPackageManager(); |
| |
| final Intent intent = new Intent(Intent.ACTION_MAIN); |
| intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); |
| final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); |
| String validPkg = ""; |
| if (ri != null) { |
| allowedPackages.add(ri.activityInfo.packageName); |
| validPkg = ri.activityInfo.packageName; |
| } |
| |
| final Intent preIntent = new Intent("com.android.setupwizard.OEM_PRE_SETUP"); |
| preIntent.addCategory(Intent.CATEGORY_DEFAULT); |
| final ResolveInfo preRi = pm |
| .resolveActivity(preIntent, PackageManager.MATCH_DISABLED_COMPONENTS); |
| String prePackageName = ""; |
| if (null != preRi) { |
| prePackageName = preRi.activityInfo.packageName; |
| } |
| |
| final Intent postIntent = new Intent("com.android.setupwizard.OEM_POST_SETUP"); |
| postIntent.addCategory(Intent.CATEGORY_DEFAULT); |
| final ResolveInfo postRi = pm |
| .resolveActivity(postIntent, PackageManager.MATCH_DISABLED_COMPONENTS); |
| String postPackageName = ""; |
| if (null != postRi) { |
| postPackageName = postRi.activityInfo.packageName; |
| } |
| if (!TextUtils.isEmpty(prePackageName) && !TextUtils.isEmpty(postPackageName) |
| && prePackageName.equals(postPackageName)) { |
| allowedPackages.add(prePackageName); |
| } |
| |
| final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[]{ |
| android.Manifest.permission.NETWORK_SETUP_WIZARD |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| for (PackageInfo pi : holding) { |
| if (!allowedPackages.contains(pi.packageName)) { |
| fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName |
| + " and must be revoked for security reasons [" + validPkg + "]"); |
| } |
| } |
| } |
| |
| /** |
| * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission |
| * is only held by the device managed provisioning application. |
| * <p> |
| * Only the ManagedProvisioning app should <em>ever</em> attempt to acquire this |
| * permission, since it would give those apps extremely broad access to connectivity |
| * functionality. The permission is intended to be granted to only the device managed |
| * provisioning. |
| */ |
| public void testNetworkManagedProvisioningPermission() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final PackageManager pm = getContext().getPackageManager(); |
| |
| // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the |
| // managed provisioning app. |
| // Ensure that the package exists. |
| final Intent intent = new Intent(Intent.ACTION_MAIN); |
| intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME); |
| final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); |
| String validPkg = ""; |
| if (ri != null) { |
| validPkg = ri.activityInfo.packageName; |
| } |
| |
| final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { |
| android.Manifest.permission.NETWORK_MANAGED_PROVISIONING |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| for (PackageInfo pi : holding) { |
| if (!Objects.equals(pi.packageName, validPkg)) { |
| fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by " |
| + pi.packageName + " and must be revoked for security reasons [" |
| + validPkg +"]"); |
| } |
| } |
| } |
| |
| /** |
| * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission |
| * is held by at most one application. |
| */ |
| public void testWifiSetDeviceMobilityStatePermission() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final PackageManager pm = getContext().getPackageManager(); |
| |
| final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { |
| android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| |
| List<String> uniquePackageNames = holding |
| .stream() |
| .map(pi -> pi.packageName) |
| .distinct() |
| .collect(Collectors.toList()); |
| |
| if (uniquePackageNames.size() > 1) { |
| fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one " |
| + "application, but is held by " + uniquePackageNames.size() + " applications: " |
| + String.join(", ", uniquePackageNames)); |
| } |
| } |
| |
| /** |
| * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission |
| * is held by at most one application. |
| */ |
| public void testNetworkCarrierProvisioningPermission() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final PackageManager pm = getContext().getPackageManager(); |
| |
| final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { |
| android.Manifest.permission.NETWORK_CARRIER_PROVISIONING |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| |
| List<String> uniquePackageNames = holding |
| .stream() |
| .map(pi -> pi.packageName) |
| .distinct() |
| .collect(Collectors.toList()); |
| |
| if (uniquePackageNames.size() > 2) { |
| fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two " |
| + "applications, but is held by " + uniquePackageNames.size() + " applications: " |
| + String.join(", ", uniquePackageNames)); |
| } |
| } |
| |
| /** |
| * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE} |
| * permission is held by at most one application. |
| */ |
| public void testUpdateWifiUsabilityStatsScorePermission() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| final PackageManager pm = getContext().getPackageManager(); |
| |
| final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { |
| android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE |
| }, PackageManager.MATCH_UNINSTALLED_PACKAGES); |
| |
| Set<String> uniqueNonSystemPackageNames = new HashSet<>(); |
| for (PackageInfo pi : holding) { |
| String packageName = pi.packageName; |
| // Shell is allowed to hold this permission for testing. |
| int uid = -1; |
| try { |
| uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); |
| } catch (PackageManager.NameNotFoundException e) { |
| continue; |
| } |
| if (uid == Process.SHELL_UID) continue; |
| |
| uniqueNonSystemPackageNames.add(packageName); |
| } |
| |
| if (uniqueNonSystemPackageNames.size() > 1) { |
| fail("The WIFI_UPDATE_USABILITY_STATS_SCORE permission must not be held by more than " |
| + "one application, but is held by " + uniqueNonSystemPackageNames.size() |
| + " applications: " + String.join(", ", uniqueNonSystemPackageNames)); |
| } |
| } |
| |
| private void turnScreenOnNoDelay() throws Exception { |
| mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); |
| mUiDevice.executeShellCommand("wm dismiss-keyguard"); |
| } |
| |
| private void turnScreenOn() throws Exception { |
| turnScreenOnNoDelay(); |
| // Since the screen on/off intent is ordered, they will not be sent right now. |
| Thread.sleep(DURATION_SCREEN_TOGGLE); |
| } |
| |
| private void turnScreenOffNoDelay() throws Exception { |
| mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); |
| } |
| |
| private void turnScreenOff() throws Exception { |
| turnScreenOffNoDelay(); |
| // Since the screen on/off intent is ordered, they will not be sent right now. |
| Thread.sleep(DURATION_SCREEN_TOGGLE); |
| } |
| |
| private void assertWifiScanningIsOn() { |
| if (!mWifiManager.isScanAlwaysAvailable()) { |
| fail("Wi-Fi scanning should be on."); |
| } |
| } |
| |
| private void runWithScanningEnabled(ThrowingRunnable r) throws Exception { |
| boolean wasScanEnabledForTest = false; |
| if (!mWifiManager.isScanAlwaysAvailable()) { |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.setScanAlwaysAvailable(true)); |
| wasScanEnabledForTest = true; |
| } |
| try { |
| r.run(); |
| } finally { |
| if (wasScanEnabledForTest) { |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.setScanAlwaysAvailable(false)); |
| } |
| } |
| } |
| |
| /** |
| * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled |
| * but location is on. |
| * @throws Exception |
| */ |
| public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| if (!hasLocationFeature()) { |
| // skip the test if location is not supported |
| return; |
| } |
| if (!isLocationEnabled()) { |
| fail("Please enable location for this test - since Marshmallow WiFi scan results are" |
| + " empty when location is disabled!"); |
| } |
| runWithScanningEnabled(() -> { |
| setWifiEnabled(false); |
| turnScreenOn(); |
| assertWifiScanningIsOn(); |
| // Toggle screen and verify Wi-Fi scanning is still on. |
| turnScreenOff(); |
| assertWifiScanningIsOn(); |
| turnScreenOn(); |
| assertWifiScanningIsOn(); |
| }); |
| } |
| |
| /** |
| * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled. |
| * @throws Exception |
| */ |
| public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| if (!hasLocationFeature()) { |
| // skip the test if location is not supported |
| return; |
| } |
| if (!isLocationEnabled()) { |
| fail("Please enable location for this test - since Marshmallow WiFi scan results are" |
| + " empty when location is disabled!"); |
| } |
| runWithScanningEnabled(() -> { |
| setWifiEnabled(true); |
| turnScreenOn(); |
| assertWifiScanningIsOn(); |
| // Toggle screen and verify Wi-Fi scanning is still on. |
| turnScreenOff(); |
| assertWifiScanningIsOn(); |
| turnScreenOn(); |
| assertWifiScanningIsOn(); |
| }); |
| } |
| |
| /** |
| * Verify that the platform supports a reasonable number of suggestions per app. |
| * @throws Exception |
| */ |
| public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| assertTrue(mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp() |
| > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP); |
| } |
| |
| private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback) |
| throws Exception { |
| // Register callback to get SoftApCapability |
| mWifiManager.registerSoftApCallback(executor, callback); |
| PollingCheck.check( |
| "SoftAp register failed!", 1_000, |
| () -> { |
| executor.runAll(); |
| // Verify callback is run on the supplied executor and called |
| return callback.getOnStateChangedCalled() && |
| callback.getOnSoftapInfoChangedCalledCount() > 0 && |
| callback.getOnSoftApCapabilityChangedCalled() && |
| callback.getOnConnectedClientCalled(); |
| }); |
| } |
| |
| private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) { |
| mWifiManager.setSoftApConfiguration(targetConfig); |
| // Bssid set dodesn't support for tethered hotspot |
| SoftApConfiguration currentConfig = mWifiManager.getSoftApConfiguration(); |
| compareSoftApConfiguration(targetConfig, currentConfig); |
| } |
| |
| private void compareSoftApConfiguration(SoftApConfiguration currentConfig, |
| SoftApConfiguration testSoftApConfig) { |
| assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid()); |
| assertEquals(currentConfig.getBssid(), testSoftApConfig.getBssid()); |
| assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType()); |
| assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase()); |
| assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid()); |
| assertEquals(currentConfig.getBand(), testSoftApConfig.getBand()); |
| assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel()); |
| assertEquals(currentConfig.getMaxNumberOfClients(), |
| testSoftApConfig.getMaxNumberOfClients()); |
| assertEquals(currentConfig.isAutoShutdownEnabled(), |
| testSoftApConfig.isAutoShutdownEnabled()); |
| assertEquals(currentConfig.getShutdownTimeoutMillis(), |
| testSoftApConfig.getShutdownTimeoutMillis()); |
| assertEquals(currentConfig.isClientControlByUserEnabled(), |
| testSoftApConfig.isClientControlByUserEnabled()); |
| assertEquals(currentConfig.getAllowedClientList(), |
| testSoftApConfig.getAllowedClientList()); |
| assertEquals(currentConfig.getBlockedClientList(), |
| testSoftApConfig.getBlockedClientList()); |
| } |
| |
| private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception { |
| if (mWifiManager.isWifiEnabled()) { |
| Log.d(TAG, "Turn off WiFi"); |
| mWifiManager.setWifiEnabled(false); |
| PollingCheck.check( |
| "Wifi turn off failed!", 2_000, |
| () -> mWifiManager.isWifiEnabled() == false); |
| } |
| if (mWifiManager.isWifiApEnabled()) { |
| mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); |
| Log.d(TAG, "Turn off tethered Hotspot"); |
| PollingCheck.check( |
| "SoftAp turn off failed!", 2_000, |
| () -> mWifiManager.isWifiApEnabled() == false); |
| mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); |
| } |
| } |
| |
| /** |
| * Verify that the configuration from getSoftApConfiguration is same as the configuration which |
| * set by setSoftApConfiguration. And depends softap capability callback to test different |
| * configuration. |
| * @throws Exception |
| */ |
| public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // check that softap mode is supported by the device |
| if (!mWifiManager.isPortableHotspotSupported()) { |
| return; |
| } |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| TestExecutor executor = new TestExecutor(); |
| TestSoftApCallback callback = new TestSoftApCallback(mLock); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| turnOffWifiAndTetheredHotspotIfEnabled(); |
| verifyRegisterSoftApCallback(executor, callback); |
| |
| SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder() |
| .setSsid(TEST_SSID_UNQUOTED) |
| .setBssid(TEST_MAC) |
| .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setAutoShutdownEnabled(true) |
| .setShutdownTimeoutMillis(100000) |
| .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ) |
| .setHiddenSsid(false); |
| |
| // Test SoftApConfiguration set and get |
| verifySetGetSoftApConfig(softApConfigBuilder.build()); |
| |
| // Test CLIENT_FORCE_DISCONNECT supported config. |
| if (callback.getCurrentSoftApCapability() |
| .areFeaturesSupported( |
| SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { |
| softApConfigBuilder.setMaxNumberOfClients(10); |
| softApConfigBuilder.setClientControlByUserEnabled(true); |
| softApConfigBuilder.setBlockedClientList(new ArrayList<>()); |
| softApConfigBuilder.setAllowedClientList(new ArrayList<>()); |
| verifySetGetSoftApConfig(softApConfigBuilder.build()); |
| } |
| |
| // Test SAE config |
| if (callback.getCurrentSoftApCapability() |
| .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) { |
| softApConfigBuilder |
| .setPassphrase(TEST_PASSPHRASE, |
| SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); |
| verifySetGetSoftApConfig(softApConfigBuilder.build()); |
| softApConfigBuilder |
| .setPassphrase(TEST_PASSPHRASE, |
| SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); |
| verifySetGetSoftApConfig(softApConfigBuilder.build()); |
| } |
| } finally { |
| mWifiManager.unregisterSoftApCallback(callback); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Verify that startTetheredHotspot with specific channel config. |
| * @throws Exception |
| */ |
| public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback() |
| throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // check that softap mode is supported by the device |
| if (!mWifiManager.isPortableHotspotSupported()) { |
| return; |
| } |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| TestExecutor executor = new TestExecutor(); |
| TestSoftApCallback callback = new TestSoftApCallback(mLock); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| turnOffWifiAndTetheredHotspotIfEnabled(); |
| verifyRegisterSoftApCallback(executor, callback); |
| |
| SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder() |
| .setSsid(TEST_SSID_UNQUOTED) |
| .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setChannel(11, SoftApConfiguration.BAND_2GHZ) // Channel 11 = Freq 2462 |
| .build(); |
| |
| mWifiManager.setSoftApConfiguration(testSoftApConfig); |
| |
| // start tethering which used to verify startTetheredHotspot |
| mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor, |
| new TetheringManager.StartTetheringCallback() { |
| @Override |
| public void onTetheringFailed(final int result) { |
| } |
| }); |
| |
| // Verify state and info callback value as expected |
| PollingCheck.check( |
| "SoftAp channel and state mismatch!!!", 5_000, |
| () -> { |
| executor.runAll(); |
| return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState() |
| && (callback.getOnSoftapInfoChangedCalledCount() > 1 |
| ? 2462 == callback.getCurrentSoftApInfo().getFrequency() : true); |
| }); |
| |
| // stop tethering which used to verify stopSoftAp |
| mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); |
| |
| // Verify clean up |
| PollingCheck.check( |
| "Stop Softap failed", 2_000, |
| () -> { |
| executor.runAll(); |
| return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() && |
| 0 == callback.getCurrentSoftApInfo().getBandwidth() && |
| 0 == callback.getCurrentSoftApInfo().getFrequency(); |
| }); |
| } finally { |
| mWifiManager.unregisterSoftApCallback(callback); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| private static class TestActionListener implements WifiManager.ActionListener { |
| private final Object mLock; |
| public boolean onSuccessCalled = false; |
| public boolean onFailedCalled = false; |
| public int failureReason = -1; |
| |
| TestActionListener(Object lock) { |
| mLock = lock; |
| } |
| |
| @Override |
| public void onSuccess() { |
| synchronized (mLock) { |
| onSuccessCalled = true; |
| mLock.notify(); |
| } |
| } |
| |
| @Override |
| public void onFailure(int reason) { |
| synchronized (mLock) { |
| onFailedCalled = true; |
| failureReason = reason; |
| mLock.notify(); |
| } |
| } |
| } |
| |
| /** |
| * Triggers connection to one of the saved networks using {@link WifiManager#connect( |
| * int, WifiManager.ActionListener)} or {@link WifiManager#connect(WifiConfiguration, |
| * WifiManager.ActionListener)} |
| * |
| * @param withNetworkId Use networkId for triggering connection, false for using |
| * WifiConfiguration. |
| * @throws Exception |
| */ |
| private void testConnect(boolean withNetworkId) throws Exception { |
| TestActionListener actionListener = new TestActionListener(mLock); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| List<WifiConfiguration> savedNetworks = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // These below API's only work with privileged permissions (obtained via shell identity |
| // for test) |
| savedNetworks = mWifiManager.getConfiguredNetworks(); |
| |
| // Disable all the saved networks to trigger disconnect & disable autojoin. |
| for (WifiConfiguration network : savedNetworks) { |
| assertTrue(mWifiManager.disableNetwork(network.networkId)); |
| } |
| waitForDisconnection(); |
| |
| // Now trigger connection to the first saved network. |
| synchronized (mLock) { |
| try { |
| if (withNetworkId) { |
| mWifiManager.connect(savedNetworks.get(0).networkId, actionListener); |
| } else { |
| mWifiManager.connect(savedNetworks.get(0), actionListener); |
| } |
| // now wait for callback |
| mLock.wait(TEST_WAIT_DURATION_MS); |
| } catch (InterruptedException e) { |
| } |
| } |
| // check if we got the success callback |
| assertTrue(actionListener.onSuccessCalled); |
| // Wait for connection to complete & ensure we are connected to the saved network. |
| waitForConnection(); |
| assertEquals(savedNetworks.get(0).networkId, |
| mWifiManager.getConnectionInfo().getNetworkId()); |
| } finally { |
| // Re-enable all saved networks before exiting. |
| if (savedNetworks != null) { |
| for (WifiConfiguration network : savedNetworks) { |
| mWifiManager.enableNetwork(network.networkId, true); |
| } |
| } |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#connect(int, WifiManager.ActionListener)} to an existing saved |
| * network. |
| */ |
| public void testConnectWithNetworkId() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| testConnect(true); |
| } |
| |
| /** |
| * Tests {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)} to an |
| * existing saved network. |
| */ |
| public void testConnectWithWifiConfiguration() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| testConnect(false); |
| |
| } |
| |
| private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { |
| private final Object mLock; |
| public boolean onAvailableCalled = false; |
| public Network network; |
| public NetworkCapabilities networkCapabilities; |
| |
| TestNetworkCallback(Object lock) { |
| mLock = lock; |
| } |
| |
| @Override |
| public void onAvailable(Network network, NetworkCapabilities networkCapabilities, |
| LinkProperties linkProperties, boolean blocked) { |
| synchronized (mLock) { |
| onAvailableCalled = true; |
| this.network = network; |
| this.networkCapabilities = networkCapabilities; |
| mLock.notify(); |
| } |
| } |
| } |
| |
| private void waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered) { |
| TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock); |
| synchronized (mLock) { |
| try { |
| NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder() |
| .addTransportType(TRANSPORT_WIFI); |
| if (expectMetered) { |
| networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_METERED); |
| } else { |
| networkRequestBuilder.addCapability(NET_CAPABILITY_NOT_METERED); |
| } |
| // File a request for wifi network. |
| mConnectivityManager.registerNetworkCallback( |
| networkRequestBuilder.build(), networkCallbackListener); |
| // now wait for callback |
| mLock.wait(TEST_WAIT_DURATION_MS); |
| } catch (InterruptedException e) { |
| } |
| } |
| assertTrue(networkCallbackListener.onAvailableCalled); |
| } |
| |
| /** |
| * Tests {@link WifiManager#save(WifiConfiguration, WifiManager.ActionListener)} by marking |
| * an existing saved network metered. |
| */ |
| public void testSave() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| TestActionListener actionListener = new TestActionListener(mLock); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| List<WifiConfiguration> savedNetworks = null; |
| WifiConfiguration savedNetwork = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // These below API's only work with privileged permissions (obtained via shell identity |
| // for test) |
| savedNetworks = mWifiManager.getConfiguredNetworks(); |
| |
| // Ensure that the saved network is not metered. |
| savedNetwork = savedNetworks.get(0); |
| assertNotEquals("Ensure that the saved network is configured as unmetered", |
| savedNetwork.meteredOverride, |
| WifiConfiguration.METERED_OVERRIDE_METERED); |
| |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| |
| // Check the network capabilities to ensure that the network is marked not metered. |
| waitForNetworkCallbackAndCheckForMeteredness(false); |
| |
| // Now mark the network metered and save. |
| synchronized (mLock) { |
| try { |
| WifiConfiguration modSavedNetwork = new WifiConfiguration(savedNetwork); |
| modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED; |
| mWifiManager.save(modSavedNetwork, actionListener); |
| // now wait for callback |
| mLock.wait(TEST_WAIT_DURATION_MS); |
| } catch (InterruptedException e) { |
| } |
| } |
| // check if we got the success callback |
| assertTrue(actionListener.onSuccessCalled); |
| // Ensure we disconnected on marking the network metered & connect back. |
| waitForDisconnection(); |
| waitForConnection(); |
| // Check the network capabilities to ensure that the network is marked metered now. |
| waitForNetworkCallbackAndCheckForMeteredness(true); |
| |
| } finally { |
| // Restore original network config (restore the meteredness back); |
| if (savedNetwork != null) { |
| mWifiManager.updateNetwork(savedNetwork); |
| } |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#forget(int, WifiManager.ActionListener)} by adding/removing a new |
| * network. |
| */ |
| public void testForget() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| TestActionListener actionListener = new TestActionListener(mLock); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int newNetworkId = INVALID_NETWORK_ID; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // These below API's only work with privileged permissions (obtained via shell identity |
| // for test) |
| List<WifiConfiguration> savedNetworks = mWifiManager.getConfiguredNetworks(); |
| |
| WifiConfiguration newOpenNetwork = new WifiConfiguration(); |
| newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\""; |
| newNetworkId = mWifiManager.addNetwork(newOpenNetwork); |
| assertNotEquals(INVALID_NETWORK_ID, newNetworkId); |
| |
| assertEquals(savedNetworks.size() + 1, mWifiManager.getConfiguredNetworks().size()); |
| |
| // Now remove the network |
| synchronized (mLock) { |
| try { |
| mWifiManager.forget(newNetworkId, actionListener); |
| // now wait for callback |
| mLock.wait(TEST_WAIT_DURATION_MS); |
| } catch (InterruptedException e) { |
| } |
| } |
| // check if we got the success callback |
| assertTrue(actionListener.onSuccessCalled); |
| |
| // Ensure that the new network has been successfully removed. |
| assertEquals(savedNetworks.size(), mWifiManager.getConfiguredNetworks().size()); |
| } finally { |
| // For whatever reason, if the forget fails, try removing using the public remove API. |
| if (newNetworkId != INVALID_NETWORK_ID) mWifiManager.removeNetwork(newNetworkId); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#getFactoryMacAddresses()} returns at least one valid MAC address. |
| */ |
| public void testGetFactoryMacAddresses() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| TestActionListener actionListener = new TestActionListener(mLock); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int newNetworkId = INVALID_NETWORK_ID; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // Obtain the factory MAC address |
| String[] macAddresses = mWifiManager.getFactoryMacAddresses(); |
| assertTrue("At list one MAC address should be returned.", macAddresses.length > 0); |
| try { |
| MacAddress mac = MacAddress.fromString(macAddresses[0]); |
| assertNotEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mac); |
| assertFalse(MacAddressUtils.isMulticastAddress(mac)); |
| } catch (IllegalArgumentException e) { |
| fail("Factory MAC address is invalid"); |
| } |
| } finally { |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#isApMacRandomizationSupported()} does not crash. |
| */ |
| public void testIsApMacRandomizationSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isApMacRandomizationSupported(); |
| } |
| |
| /** |
| * Tests {@link WifiManager#isConnectedMacRandomizationSupported()} does not crash. |
| */ |
| public void testIsConnectedMacRandomizationSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isConnectedMacRandomizationSupported(); |
| } |
| |
| /** |
| * Tests {@link WifiManager#isPreferredNetworkOffloadSupported()} does not crash. |
| */ |
| public void testIsPreferredNetworkOffloadSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isPreferredNetworkOffloadSupported(); |
| } |
| |
| /** Test that PNO scans reconnects us when the device is disconnected and the screen is off. */ |
| public void testPnoScan() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| if (!mWifiManager.isPreferredNetworkOffloadSupported()) { |
| // skip the test if PNO scanning is not supported |
| return; |
| } |
| |
| // make sure we're connected |
| waitForConnection(); |
| |
| WifiInfo currentNetwork = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getConnectionInfo); |
| |
| // disable all networks that aren't already disabled |
| List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getConfiguredNetworks); |
| Set<Integer> disabledNetworkIds = new HashSet<>(); |
| for (WifiConfiguration config : savedNetworks) { |
| if (config.getNetworkSelectionStatus().getNetworkSelectionDisableReason() |
| == WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE) { |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.disableNetwork(config.networkId)); |
| disabledNetworkIds.add(config.networkId); |
| } |
| } |
| |
| try { |
| // wait for disconnection from current network |
| waitForDisconnection(); |
| |
| // turn screen off |
| turnScreenOffNoDelay(); |
| |
| // re-enable the current network - this will trigger PNO |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.enableNetwork(currentNetwork.getNetworkId(), false)); |
| disabledNetworkIds.remove(currentNetwork.getNetworkId()); |
| |
| // PNO should reconnect us back to the network we disconnected from |
| waitForConnection(); |
| } finally { |
| // re-enable disabled networks |
| for (int disabledNetworkId : disabledNetworkIds) { |
| ShellIdentityUtils.invokeWithShellPermissions( |
| () -> mWifiManager.enableNetwork(disabledNetworkId, true)); |
| } |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#isTdlsSupported()} does not crash. |
| */ |
| public void testIsTdlsSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isTdlsSupported(); |
| } |
| |
| /** |
| * Tests {@link WifiManager#isStaApConcurrencySupported(). |
| */ |
| public void testIsStaApConcurrencySupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // check that softap mode is supported by the device |
| if (!mWifiManager.isPortableHotspotSupported()) { |
| return; |
| } |
| assertTrue(mWifiManager.isWifiEnabled()); |
| |
| boolean isStaApConcurrencySupported = mWifiManager.isStaApConcurrencySupported(); |
| // start local only hotspot. |
| TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); |
| if (isStaApConcurrencySupported) { |
| assertTrue(mWifiManager.isWifiEnabled()); |
| } else { |
| // no concurrency, wifi should be disabled. |
| assertFalse(mWifiManager.isWifiEnabled()); |
| } |
| stopLocalOnlyHotspot(callback, true); |
| |
| assertTrue(mWifiManager.isWifiEnabled()); |
| } |
| |
| /** |
| * state is a bitset, where bit 0 indicates whether there was data in, and bit 1 indicates |
| * whether there was data out. Only count down on the latch once there was both data in and out. |
| */ |
| private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback { |
| public final CountDownLatch latch = new CountDownLatch(1); |
| private int mAccumulator = 0; |
| |
| @Override |
| public void onStateChanged(int state) { |
| mAccumulator |= state; |
| if (mAccumulator == DATA_ACTIVITY_INOUT) { |
| latch.countDown(); |
| } |
| } |
| } |
| |
| private void sendTraffic() { |
| boolean didAnyConnectionSucceed = false; |
| for (int i = 0; i < 10; i++) { |
| // Do some network operations |
| HttpURLConnection connection = null; |
| try { |
| URL url = new URL("http://www.google.com/"); |
| connection = (HttpURLConnection) url.openConnection(); |
| connection.setInstanceFollowRedirects(false); |
| connection.setConnectTimeout(TEST_WAIT_DURATION_MS); |
| connection.setReadTimeout(TEST_WAIT_DURATION_MS); |
| connection.setUseCaches(false); |
| InputStream stream = connection.getInputStream(); |
| byte[] bytes = new byte[100]; |
| int receivedBytes = stream.read(bytes); |
| if (receivedBytes > 0) { |
| didAnyConnectionSucceed = true; |
| } |
| } catch (Exception e) { |
| // ignore |
| } finally { |
| if (connection != null) connection.disconnect(); |
| } |
| } |
| assertTrue("All connections failed!", didAnyConnectionSucceed); |
| } |
| |
| /** |
| * Tests {@link WifiManager#registerTrafficStateCallback(Executor, |
| * WifiManager.TrafficStateCallback)} by sending some traffic. |
| */ |
| public void testTrafficStateCallback() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| TestTrafficStateCallback callback = new TestTrafficStateCallback(); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| |
| // Turn screen on for wifi traffic polling. |
| turnScreenOn(); |
| mWifiManager.registerTrafficStateCallback( |
| Executors.newSingleThreadExecutor(), callback); |
| // Send some traffic to trigger the traffic state change callbacks. |
| sendTraffic(); |
| // now wait for callback |
| boolean success = callback.latch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS); |
| // check if we got the state changed callback with both data in and out |
| assertTrue(success); |
| } finally { |
| turnScreenOff(); |
| mWifiManager.unregisterTrafficStateCallback(callback); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#setScanAlwaysAvailable(boolean)} & |
| * {@link WifiManager#isScanAlwaysAvailable()}. |
| */ |
| public void testScanAlwaysAvailable() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| Boolean currState = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| currState = mWifiManager.isScanAlwaysAvailable(); |
| boolean newState = !currState; |
| mWifiManager.setScanAlwaysAvailable(newState); |
| PollingCheck.check( |
| "Wifi settings toggle failed!", |
| DURATION_SETTINGS_TOGGLE, |
| () -> mWifiManager.isScanAlwaysAvailable() == newState); |
| assertEquals(newState, mWifiManager.isScanAlwaysAvailable()); |
| } finally { |
| if (currState != null) mWifiManager.setScanAlwaysAvailable(currState); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#setScanThrottleEnabled(boolean)} & |
| * {@link WifiManager#isScanThrottleEnabled()}. |
| */ |
| public void testScanThrottleEnabled() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| Boolean currState = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| currState = mWifiManager.isScanThrottleEnabled(); |
| boolean newState = !currState; |
| mWifiManager.setScanThrottleEnabled(newState); |
| PollingCheck.check( |
| "Wifi settings toggle failed!", |
| DURATION_SETTINGS_TOGGLE, |
| () -> mWifiManager.isScanThrottleEnabled() == newState); |
| assertEquals(newState, mWifiManager.isScanThrottleEnabled()); |
| } finally { |
| if (currState != null) mWifiManager.setScanThrottleEnabled(currState); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#setAutoWakeupEnabled(boolean)} & |
| * {@link WifiManager#isAutoWakeupEnabled()}. |
| */ |
| public void testAutoWakeUpEnabled() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| Boolean currState = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| currState = mWifiManager.isAutoWakeupEnabled(); |
| boolean newState = !currState; |
| mWifiManager.setAutoWakeupEnabled(newState); |
| PollingCheck.check( |
| "Wifi settings toggle failed!", |
| DURATION_SETTINGS_TOGGLE, |
| () -> mWifiManager.isAutoWakeupEnabled() == newState); |
| assertEquals(newState, mWifiManager.isAutoWakeupEnabled()); |
| } finally { |
| if (currState != null) mWifiManager.setAutoWakeupEnabled(currState); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#setVerboseLoggingEnabled(boolean)} & |
| * {@link WifiManager#isVerboseLoggingEnabled()}. |
| */ |
| public void testVerboseLoggingEnabled() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| Boolean currState = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| currState = mWifiManager.isVerboseLoggingEnabled(); |
| boolean newState = !currState; |
| mWifiManager.setVerboseLoggingEnabled(newState); |
| PollingCheck.check( |
| "Wifi settings toggle failed!", |
| DURATION_SETTINGS_TOGGLE, |
| () -> mWifiManager.isVerboseLoggingEnabled() == newState); |
| assertEquals(newState, mWifiManager.isVerboseLoggingEnabled()); |
| } finally { |
| if (currState != null) mWifiManager.setVerboseLoggingEnabled(currState); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#factoryReset()} cannot be invoked from a non-privileged app. |
| * |
| * Note: This intentionally does not test the full reset functionality because it causes |
| * the existing saved networks on the device to be lost after the test. If you add the |
| * networks back after reset, the ownership of saved networks will change. |
| */ |
| public void testFactoryReset() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| List<WifiConfiguration> beforeSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getConfiguredNetworks); |
| try { |
| mWifiManager.factoryReset(); |
| fail("Factory reset should not be allowed for non-privileged apps"); |
| } catch (SecurityException e) { |
| // expected |
| } |
| List<WifiConfiguration> afterSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getConfiguredNetworks); |
| assertEquals(beforeSavedNetworks.size(), afterSavedNetworks.size()); |
| } |
| |
| /** |
| * Test {@link WifiNetworkConnectionStatistics} does not crash. |
| * TODO(b/150891569): deprecate it in Android S, this API is not used anywhere. |
| */ |
| public void testWifiNetworkConnectionStatistics() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| new WifiNetworkConnectionStatistics(); |
| WifiNetworkConnectionStatistics stats = new WifiNetworkConnectionStatistics(0, 0); |
| new WifiNetworkConnectionStatistics(stats); |
| } |
| |
| /** |
| * Test that the wifi country code is either null, or a length-2 string. |
| */ |
| public void testGetCountryCode() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| String wifiCountryCode = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getCountryCode); |
| |
| if (wifiCountryCode == null) { |
| return; |
| } |
| assertEquals(2, wifiCountryCode.length()); |
| |
| // assert that the country code is all uppercase |
| assertEquals(wifiCountryCode.toUpperCase(Locale.US), wifiCountryCode); |
| |
| if (WifiFeature.isTelephonySupported(getContext())) { |
| String telephonyCountryCode = getContext().getSystemService(TelephonyManager.class) |
| .getNetworkCountryIso(); |
| assertEquals(telephonyCountryCode, wifiCountryCode.toLowerCase(Locale.US)); |
| } |
| } |
| |
| /** |
| * Test that {@link WifiManager#getCurrentNetwork()} returns a Network obeject consistent |
| * with {@link ConnectivityManager#registerNetworkCallback} when connected to a Wifi network, |
| * and returns null when not connected. |
| */ |
| public void testGetCurrentNetwork() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| // ensure Wifi is connected |
| ShellIdentityUtils.invokeWithShellPermissions(() -> mWifiManager.reconnect()); |
| PollingCheck.check( |
| "Wifi not connected - Please ensure there is a saved network in range of this " |
| + "device", |
| WIFI_CONNECT_TIMEOUT_MILLIS, |
| () -> mWifiManager.getConnectionInfo().getNetworkId() != -1); |
| |
| Network wifiCurrentNetwork = ShellIdentityUtils.invokeWithShellPermissions( |
| mWifiManager::getCurrentNetwork); |
| assertNotNull(wifiCurrentNetwork); |
| |
| TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock); |
| synchronized (mLock) { |
| try { |
| // File a request for wifi network. |
| mConnectivityManager.registerNetworkCallback( |
| new NetworkRequest.Builder() |
| .addTransportType(TRANSPORT_WIFI) |
| .build(), |
| networkCallbackListener); |
| // now wait for callback |
| mLock.wait(TEST_WAIT_DURATION_MS); |
| } catch (InterruptedException e) { |
| } |
| } |
| assertTrue(networkCallbackListener.onAvailableCalled); |
| Network connectivityCurrentNetwork = networkCallbackListener.network; |
| assertEquals(connectivityCurrentNetwork, wifiCurrentNetwork); |
| |
| setWifiEnabled(false); |
| PollingCheck.check( |
| "Wifi not disconnected!", |
| 20000, |
| () -> mWifiManager.getConnectionInfo().getNetworkId() == -1); |
| |
| assertNull(ShellIdentityUtils.invokeWithShellPermissions(mWifiManager::getCurrentNetwork)); |
| } |
| |
| /** |
| * Tests {@link WifiManager#isWpa3SaeSupported()} does not crash. |
| */ |
| public void testIsWpa3SaeSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isWpa3SaeSupported(); |
| } |
| |
| /** |
| * Tests {@link WifiManager#isWpa3SuiteBSupported()} does not crash. |
| */ |
| public void testIsWpa3SuiteBSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isWpa3SuiteBSupported(); |
| } |
| |
| /** |
| * Tests {@link WifiManager#isEnhancedOpenSupported()} does not crash. |
| */ |
| public void testIsEnhancedOpenSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isEnhancedOpenSupported(); |
| } |
| |
| /** |
| * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in |
| * both WiFi enabled/disabled states. |
| * Note that the response depends on device support and hence both true/false |
| * are valid responses. |
| */ |
| public void testIs5GhzBandSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| // Check for 5GHz support with wifi enabled |
| setWifiEnabled(true); |
| PollingCheck.check( |
| "Wifi not enabled!", |
| 20000, |
| () -> mWifiManager.isWifiEnabled()); |
| boolean isSupportedEnabled = mWifiManager.is5GHzBandSupported(); |
| |
| // Check for 5GHz support with wifi disabled |
| setWifiEnabled(false); |
| PollingCheck.check( |
| "Wifi not disabled!", |
| 20000, |
| () -> !mWifiManager.isWifiEnabled()); |
| boolean isSupportedDisabled = mWifiManager.is5GHzBandSupported(); |
| |
| // If Support is true when WiFi is disable, then it has to be true when it is enabled. |
| // Note, the reverse is a valid case. |
| if (isSupportedDisabled) { |
| assertTrue(isSupportedEnabled); |
| } |
| } |
| |
| /** |
| * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in |
| * both Wifi enabled/disabled states. |
| * Note that the response depends on device support and hence both true/false |
| * are valid responses. |
| */ |
| public void testIs6GhzBandSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| // Check for 6GHz support with wifi enabled |
| setWifiEnabled(true); |
| PollingCheck.check( |
| "Wifi not enabled!", |
| 20000, |
| () -> mWifiManager.isWifiEnabled()); |
| boolean isSupportedEnabled = mWifiManager.is6GHzBandSupported(); |
| |
| // Check for 6GHz support with wifi disabled |
| setWifiEnabled(false); |
| PollingCheck.check( |
| "Wifi not disabled!", |
| 20000, |
| () -> !mWifiManager.isWifiEnabled()); |
| boolean isSupportedDisabled = mWifiManager.is6GHzBandSupported(); |
| |
| // If Support is true when WiFi is disable, then it has to be true when it is enabled. |
| // Note, the reverse is a valid case. |
| if (isSupportedDisabled) { |
| assertTrue(isSupportedEnabled); |
| } |
| } |
| |
| /** |
| * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in |
| * both Wifi enabled/disabled states. The test is to be performed on |
| * {@link WifiAnnotations}'s {@code WIFI_STANDARD_} |
| * Note that the response depends on device support and hence both true/false |
| * are valid responses. |
| */ |
| public void testIsWifiStandardsSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| // Check for WiFi standards support with wifi enabled |
| setWifiEnabled(true); |
| PollingCheck.check( |
| "Wifi not enabled!", |
| 20000, |
| () -> mWifiManager.isWifiEnabled()); |
| boolean isLegacySupportedEnabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); |
| boolean is11nSupporedEnabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); |
| boolean is11acSupportedEnabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); |
| boolean is11axSupportedEnabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); |
| |
| // Check for WiFi standards support with wifi disabled |
| setWifiEnabled(false); |
| PollingCheck.check( |
| "Wifi not disabled!", |
| 20000, |
| () -> !mWifiManager.isWifiEnabled()); |
| |
| boolean isLegacySupportedDisabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); |
| boolean is11nSupportedDisabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); |
| boolean is11acSupportedDisabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); |
| boolean is11axSupportedDisabled = |
| mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); |
| |
| if (isLegacySupportedDisabled) { |
| assertTrue(isLegacySupportedEnabled); |
| } |
| |
| if (is11nSupportedDisabled) { |
| assertTrue(is11nSupporedEnabled); |
| } |
| |
| if (is11acSupportedDisabled) { |
| assertTrue(is11acSupportedEnabled); |
| } |
| |
| if (is11axSupportedDisabled) { |
| assertTrue(is11axSupportedEnabled); |
| } |
| } |
| |
| private static PasspointConfiguration createPasspointConfiguration() { |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| homeSp.setFriendlyName("friendly name"); |
| homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66}); |
| config.setHomeSp(homeSp); |
| Credential.SimCredential simCred = new Credential.SimCredential(); |
| simCred.setImsi("123456*"); |
| simCred.setEapType(23 /* EAP_AKA */); |
| Credential cred = new Credential(); |
| cred.setRealm("realm"); |
| cred.setSimCredential(simCred); |
| config.setCredential(cred); |
| |
| return config; |
| } |
| |
| /** |
| * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)} |
| * adds a Passpoint configuration correctly by getting it once it is added, and comparing it |
| * to the local copy of the configuration. |
| */ |
| public void testAddOrUpdatePasspointConfiguration() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| // Create and install a Passpoint configuration |
| PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); |
| |
| // Compare configurations |
| List<PasspointConfiguration> configurations = mWifiManager.getPasspointConfigurations(); |
| assertNotNull("The installed passpoint profile is missing", configurations); |
| assertEquals(passpointConfiguration, getTargetPasspointConfiguration(configurations, |
| passpointConfiguration.getUniqueId())); |
| } finally { |
| // Clean up |
| mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#setPasspointMeteredOverride(String, int)} |
| * adds a Passpoint configuration correctly, check the default metered setting. Use API change |
| * metered override, verify Passpoint configuration changes with it. |
| */ |
| public void testSetPasspointMeteredOverride() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // Create and install a Passpoint configuration |
| PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); |
| String fqdn = passpointConfiguration.getHomeSp().getFqdn(); |
| String uniqueId = passpointConfiguration.getUniqueId(); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); |
| PasspointConfiguration saved = getTargetPasspointConfiguration( |
| mWifiManager.getPasspointConfigurations(), uniqueId); |
| assertNotNull("The installed passpoint profile is missing", saved); |
| // Verify meter override setting. |
| assertEquals("Metered overrider default should be none", |
| WifiConfiguration.METERED_OVERRIDE_NONE, saved.getMeteredOverride()); |
| // Change the meter override setting. |
| mWifiManager.setPasspointMeteredOverride(fqdn, |
| WifiConfiguration.METERED_OVERRIDE_METERED); |
| // Verify passpoint config change with the new setting. |
| saved = getTargetPasspointConfiguration( |
| mWifiManager.getPasspointConfigurations(), uniqueId); |
| assertNotNull("The installed passpoint profile is missing", saved); |
| assertEquals("Metered override should be metered", |
| WifiConfiguration.METERED_OVERRIDE_METERED, saved.getMeteredOverride()); |
| } finally { |
| // Clean up |
| mWifiManager.removePasspointConfiguration(fqdn); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests that |
| * {@link WifiManager#startSubscriptionProvisioning(OsuProvider, Executor, ProvisioningCallback)} |
| * starts a subscription provisioning, and confirm a status callback invoked once. |
| */ |
| public void testStartSubscriptionProvisioning() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| // Using Java reflection to construct an OsuProvider instance because its constructor is |
| // hidden and not available to apps. |
| Class<?> osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider"); |
| Constructor<?> osuProviderClassConstructor = osuProviderClass.getConstructor(String.class, |
| Map.class, String.class, Uri.class, String.class, List.class); |
| |
| OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID, |
| TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, |
| TEST_METHOD_LIST); |
| |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| synchronized (mLock) { |
| // Start a subscription provisioning for a non-existent Passpoint R2 AP |
| mWifiManager.startSubscriptionProvisioning(osuProvider, mExecutor, |
| mProvisioningCallback); |
| mLock.wait(TEST_WAIT_DURATION_MS); |
| } |
| } finally { |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| |
| // Expect only a single callback event, connecting. Since AP doesn't exist, it ends here |
| assertEquals(ProvisioningCallback.OSU_STATUS_AP_CONNECTING, mProvisioningStatus); |
| // No failure callbacks expected |
| assertEquals(0, mProvisioningFailureStatus); |
| // No completion callback expected |
| assertFalse(mProvisioningComplete); |
| } |
| |
| /** |
| * Tests {@link WifiManager#setTdlsEnabled(InetAddress, boolean)} does not crash. |
| */ |
| public void testSetTdlsEnabled() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| |
| InetAddress inetAddress = InetAddress.getByName(TEST_IP_ADDRESS); |
| |
| mWifiManager.setTdlsEnabled(inetAddress, true); |
| Thread.sleep(50); |
| mWifiManager.setTdlsEnabled(inetAddress, false); |
| } |
| |
| /** |
| * Tests {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean)} does not crash. |
| */ |
| public void testSetTdlsEnabledWithMacAddress() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| |
| mWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, true); |
| Thread.sleep(50); |
| mWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, false); |
| } |
| |
| /** |
| * Tests {@link WifiManager#getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(List)} |
| */ |
| public void testGetAllWifiConfigForMatchedNetworkSuggestion() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| ScanResult scanResult = new ScanResult(); |
| scanResult.SSID = TEST_SSID; |
| scanResult.capabilities = TEST_PSK_CAP; |
| scanResult.BSSID = TEST_BSSID; |
| List<ScanResult> testList = Arrays.asList(scanResult); |
| WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() |
| .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build(); |
| |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, |
| mWifiManager.addNetworkSuggestions(Arrays.asList(suggestion))); |
| List<WifiConfiguration> matchedResult; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| matchedResult = mWifiManager |
| .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(testList); |
| } finally { |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| // As suggestion is not approved, will return empty list. |
| assertTrue(matchedResult.isEmpty()); |
| } |
| |
| /** |
| * Tests {@link WifiManager#getMatchingScanResults(List, List)} |
| */ |
| public void testGetMatchingScanResults() { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // Create pair of ScanResult and WifiNetworkSuggestion |
| ScanResult scanResult = new ScanResult(); |
| scanResult.SSID = TEST_SSID; |
| scanResult.capabilities = TEST_PSK_CAP; |
| scanResult.BSSID = TEST_BSSID; |
| |
| WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() |
| .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build(); |
| |
| Map<WifiNetworkSuggestion, List<ScanResult>> matchedResults = mWifiManager |
| .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult)); |
| // Verify result is matched pair of ScanResult and WifiNetworkSuggestion |
| assertEquals(scanResult.SSID, matchedResults.get(suggestion).get(0).SSID); |
| |
| // Change ScanResult to unmatched should return empty result. |
| scanResult.SSID = TEST_SSID_UNQUOTED; |
| matchedResults = mWifiManager |
| .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult)); |
| assertTrue(matchedResults.get(suggestion).isEmpty()); |
| } |
| |
| /** |
| * Tests {@link WifiManager#disableEphemeralNetwork(String)}. |
| */ |
| public void testDisableEphemeralNetwork() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| List<WifiConfiguration> savedNetworks = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // Temporarily disable on all networks. |
| savedNetworks = mWifiManager.getConfiguredNetworks(); |
| for (WifiConfiguration network : savedNetworks) { |
| mWifiManager.disableEphemeralNetwork(network.SSID); |
| } |
| // trigger a disconnect and wait for disconnect. |
| mWifiManager.disconnect(); |
| waitForDisconnection(); |
| |
| // Now trigger scan and ensure that the device does not connect to any networks. |
| mWifiManager.startScan(); |
| ensureNotConnected(); |
| } finally { |
| uiAutomation.dropShellPermissionIdentity(); |
| setWifiEnabled(false); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#allowAutojoin(int, boolean)}. |
| */ |
| public void testAllowAutojoin() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| List<WifiConfiguration> savedNetworks = null; |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // disable autojoin on all networks. |
| savedNetworks = mWifiManager.getConfiguredNetworks(); |
| for (WifiConfiguration network : savedNetworks) { |
| mWifiManager.allowAutojoin(network.networkId, false); |
| } |
| // trigger a disconnect and wait for disconnect. |
| mWifiManager.disconnect(); |
| waitForDisconnection(); |
| |
| // Now trigger scan and ensure that the device does not connect to any networks. |
| mWifiManager.startScan(); |
| ensureNotConnected(); |
| |
| // Now enable autojoin on all networks. |
| for (WifiConfiguration network : savedNetworks) { |
| mWifiManager.allowAutojoin(network.networkId, true); |
| } |
| |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| } finally { |
| // Restore auto join state. |
| if (savedNetworks != null) { |
| for (WifiConfiguration network : savedNetworks) { |
| mWifiManager.allowAutojoin(network.networkId, network.allowAutojoin); |
| } |
| } |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#allowAutojoinPasspoint(String, boolean)}. |
| */ |
| public void testAllowAutojoinPasspoint() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); |
| // Turn off auto-join |
| mWifiManager.allowAutojoinPasspoint( |
| passpointConfiguration.getHomeSp().getFqdn(), false); |
| // Turn on auto-join |
| mWifiManager.allowAutojoinPasspoint( |
| passpointConfiguration.getHomeSp().getFqdn(), true); |
| } finally { |
| mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#allowAutojoinGlobal(boolean)}. |
| */ |
| public void testAllowAutojoinGlobal() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| |
| UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| try { |
| uiAutomation.adoptShellPermissionIdentity(); |
| // disable autojoin on all networks. |
| mWifiManager.allowAutojoinGlobal(false); |
| |
| // trigger a disconnect and wait for disconnect. |
| mWifiManager.disconnect(); |
| waitForDisconnection(); |
| |
| // Now trigger scan and ensure that the device does not connect to any networks. |
| mWifiManager.startScan(); |
| ensureNotConnected(); |
| |
| // Now enable autojoin on all networks. |
| mWifiManager.allowAutojoinGlobal(true); |
| |
| // Trigger a scan & wait for connection to one of the saved networks. |
| mWifiManager.startScan(); |
| waitForConnection(); |
| } finally { |
| // Re-enable auto join if the test fails for some reason. |
| mWifiManager.allowAutojoinGlobal(true); |
| uiAutomation.dropShellPermissionIdentity(); |
| } |
| } |
| |
| /** |
| * Tests {@link WifiManager#isWapiSupported()} does not crash. |
| */ |
| public void testIsWapiSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| mWifiManager.isWapiSupported(); |
| } |
| |
| /** |
| * Tests {@link WifiManager#isP2pSupported()} returns true |
| * if this device supports it, otherwise, ensure no crash. |
| */ |
| public void testIsP2pSupported() throws Exception { |
| if (!WifiFeature.isWifiSupported(getContext())) { |
| // skip the test if WiFi is not supported |
| return; |
| } |
| |
| if (WifiFeature.isP2pSupported(getContext())) { |
| // if this device supports P2P, ensure hw capability is correct. |
| assertTrue(mWifiManager.isP2pSupported()); |
| } else { |
| // ensure no crash. |
| mWifiManager.isP2pSupported(); |
| } |
| |
| } |
| |
| private PasspointConfiguration getTargetPasspointConfiguration( |
| List<PasspointConfiguration> configurationList, String uniqueId) { |
| if (configurationList == null || configurationList.isEmpty()) { |
| return null; |
| } |
| for (PasspointConfiguration config : configurationList) { |
| if (TextUtils.equals(config.getUniqueId(), uniqueId)) { |
| return config; |
| } |
| } |
| return null; |
| } |
| } |