Merge "cts: skip wifi related tests if wifi is unsupported" into oc-dev
diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml
index 9945805..ad7f81b 100644
--- a/tests/cts/hostside/AndroidTest.xml
+++ b/tests/cts/hostside/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS net host test cases">
+ <option name="config-descriptor:metadata" key="component" value="networking" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsHostsideNetworkTests.jar" />
<option name="runtime-hint" value="3m56s" />
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
index 09f3120..165f530 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
+++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
@@ -16,6 +16,7 @@
package com.android.cts.net.hostside;
-oneway interface INetworkStateObserver {
+interface INetworkStateObserver {
+ boolean isForeground();
void onNetworkStateChecked(String resultData);
}
\ No newline at end of file
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index f994169..12b338f 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -31,17 +31,20 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiManager;
+import android.os.BatteryManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.test.InstrumentationTestCase;
+import android.text.TextUtils;
import android.util.Log;
import com.android.cts.net.hostside.INetworkStateObserver;
@@ -90,11 +93,19 @@
protected static final int TYPE_COMPONENT_ACTIVTIY = 0;
protected static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1;
+ private static final int BATTERY_STATE_TIMEOUT_MS = 5000;
+ private static final int BATTERY_STATE_CHECK_INTERVAL_MS = 500;
+
private static final int FOREGROUND_PROC_NETWORK_TIMEOUT_MS = 6000;
// Must be higher than NETWORK_TIMEOUT_MS
private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4;
+ private static final IntentFilter BATTERY_CHANGED_FILTER =
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+
+ private static final String APP_NOT_FOREGROUND_ERROR = "app_not_fg";
+
protected Context mContext;
protected Instrumentation mInstrumentation;
protected ConnectivityManager mCm;
@@ -298,6 +309,7 @@
}
Log.d(TAG, "App not on foreground state on attempt #" + i
+ "; sleeping 1s before trying again");
+ turnScreenOn();
SystemClock.sleep(SECOND_IN_MS);
}
fail("App2 is not on foreground state after " + maxTries + " attempts: " + state );
@@ -722,10 +734,29 @@
protected void turnBatteryOff() throws Exception {
executeSilentShellCommand("cmd battery unplug");
+ assertBatteryState(false);
}
protected void turnBatteryOn() throws Exception {
executeSilentShellCommand("cmd battery reset");
+ assertBatteryState(true);
+
+ }
+
+ private void assertBatteryState(boolean pluggedIn) throws Exception {
+ final long endTime = SystemClock.elapsedRealtime() + BATTERY_STATE_TIMEOUT_MS;
+ while (isDevicePluggedIn() != pluggedIn && SystemClock.elapsedRealtime() <= endTime) {
+ Thread.sleep(BATTERY_STATE_CHECK_INTERVAL_MS);
+ }
+ if (isDevicePluggedIn() != pluggedIn) {
+ fail("Timed out waiting for the plugged-in state to change,"
+ + " expected pluggedIn: " + pluggedIn);
+ }
+ }
+
+ private boolean isDevicePluggedIn() {
+ final Intent batteryIntent = mContext.registerReceiver(null, BATTERY_CHANGED_FILTER);
+ return batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) > 0;
}
protected void turnScreenOff() throws Exception {
@@ -777,12 +808,40 @@
protected void setAppIdle(boolean enabled) throws Exception {
Log.i(TAG, "Setting app idle to " + enabled);
+ final String beforeStats = getUsageStatsDump();
executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled );
- assertAppIdle(enabled); // Sanity check
+ try {
+ assertAppIdle(enabled); // Sanity check
+ } catch (Throwable e) {
+ final String afterStats = getUsageStatsDump();
+ Log.d(TAG, "UsageStats before:\n" + beforeStats);
+ Log.d(TAG, "UsageStats after:\n" + afterStats);
+ throw e;
+ }
+ }
+
+ private String getUsageStatsDump() throws Exception {
+ final String output = runShellCommand(mInstrumentation, "dumpsys usagestats").trim();
+ final StringBuilder sb = new StringBuilder();
+ final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n');
+ splitter.setString(output);
+ String str;
+ while (splitter.hasNext()) {
+ str = splitter.next();
+ if (str.contains("package=")
+ && !str.contains(TEST_PKG) && !str.contains(TEST_APP2_PKG)) {
+ continue;
+ }
+ if (str.contains("config=")) {
+ continue;
+ }
+ sb.append(str).append('\n');
+ }
+ return sb.toString();
}
protected void assertAppIdle(boolean enabled) throws Exception {
- assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 10, 2, "Idle=" + enabled);
+ assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled);
}
/**
@@ -795,11 +854,12 @@
protected void registerBroadcastReceiver() throws Exception {
mServiceClient.registerBroadcastReceiver();
+ final Intent intent = new Intent(ACTION_RECEIVER_READY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
// Wait until receiver is ready.
final int maxTries = 10;
for (int i = 1; i <= maxTries; i++) {
- final String message =
- sendOrderedBroadcast(new Intent(ACTION_RECEIVER_READY), SECOND_IN_MS);
+ final String message = sendOrderedBroadcast(intent, SECOND_IN_MS * 4);
Log.d(TAG, "app2 receiver acked: " + message);
if (message != null) {
return;
@@ -848,6 +908,8 @@
return;
} else if (type == TYPE_COMPONENT_ACTIVTIY) {
turnScreenOn();
+ // Wait for screen-on state to propagate through the system.
+ SystemClock.sleep(2000);
final CountDownLatch latch = new CountDownLatch(1);
final Intent launchIntent = getIntentForComponent(type);
final Bundle extras = new Bundle();
@@ -857,7 +919,12 @@
mContext.startActivity(launchIntent);
if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
if (!errors[0].isEmpty()) {
- fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
+ if (errors[0] == APP_NOT_FOREGROUND_ERROR) {
+ // App didn't come to foreground when the activity is started, so try again.
+ assertForegroundNetworkAccess();
+ } else {
+ fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
+ }
}
} else {
fail("Timed out waiting for network availability status from app2 (" + mUid + ")");
@@ -896,8 +963,21 @@
final String[] errors) {
return new INetworkStateObserver.Stub() {
@Override
+ public boolean isForeground() {
+ try {
+ final ProcessState state = getProcessStateByUid(mUid);
+ return !isBackground(state.state);
+ } catch (Exception e) {
+ Log.d(TAG, "Error while reading the proc state for " + mUid + ": " + e);
+ return false;
+ }
+ }
+
+ @Override
public void onNetworkStateChecked(String resultData) {
- errors[0] = checkForAvailabilityInResultData(resultData, true);
+ errors[0] = resultData == null
+ ? APP_NOT_FOREGROUND_ERROR
+ : checkForAvailabilityInResultData(resultData, true);
latch.countDown();
}
};
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
index 20bbd5a..351733e 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -72,12 +72,21 @@
final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface(
extras.getBinder(KEY_NETWORK_STATE_OBSERVER));
if (observer != null) {
+ try {
+ if (!observer.isForeground()) {
+ Log.e(TAG, "App didn't come to foreground");
+ observer.onNetworkStateChecked(null);
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error occurred while reading the proc state: " + e);
+ }
AsyncTask.execute(() -> {
try {
observer.onNetworkStateChecked(
MyBroadcastReceiver.checkNetworkStatus(context));
} catch (RemoteException e) {
- Log.e(TAG, "Error occured while notifying the observer: " + e);
+ Log.e(TAG, "Error occurred while notifying the observer: " + e);
}
});
}
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
index da7e704..286cc2f 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
@@ -41,6 +41,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Log.d(TAG, "MyActivity.onCreate()");
Common.notifyNetworkStateObserver(this, getIntent());
finishCommandReceiver = new BroadcastReceiver() {
@Override
diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml
index 389b926..4a578ea 100644
--- a/tests/cts/net/AndroidTest.xml
+++ b/tests/cts/net/AndroidTest.xml
@@ -13,7 +13,8 @@
limitations under the License.
-->
<configuration description="Config for CTS Net test cases">
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="config-descriptor:metadata" key="component" value="networking" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsNetTestCases.apk" />
<option name="test-file-name" value="CtsNetTestAppForApi23.apk" />
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
index e065378..ea63f78 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -59,6 +59,7 @@
private static MySync mMySync;
private List<ScanResult> mScanResults = null;
private NetworkInfo mNetworkInfo;
+ private Object mLOHSLock = new Object();
// Please refer to WifiManager
private static final int MIN_RSSI = -100;
@@ -173,14 +174,25 @@
private void setWifiEnabled(boolean enable) throws Exception {
synchronized (mMySync) {
- assertTrue(mWifiManager.setWifiEnabled(enable));
if (mWifiManager.isWifiEnabled() != enable) {
+ // the new state is different, we expect it to change
mMySync.expectedState = STATE_WIFI_CHANGING;
- long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
- int expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
- while (System.currentTimeMillis() < timeout
- && mMySync.expectedState != expectedState)
- mMySync.wait(WAIT_MSEC);
+ } else {
+ mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
+ }
+ // now trigger the change
+ assertTrue(mWifiManager.setWifiEnabled(enable));
+ waitForExpectedWifiState(enable);
+ }
+ }
+
+ private void waitForExpectedWifiState(boolean enabled) throws InterruptedException {
+ synchronized (mMySync) {
+ long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+ int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
+ while (System.currentTimeMillis() < timeout
+ && mMySync.expectedState != expected) {
+ mMySync.wait(WAIT_MSEC);
}
}
}
@@ -373,6 +385,7 @@
wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = SSID1;
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
int netId = mWifiManager.addNetwork(wifiConfiguration);
assertTrue(existSSID(SSID1));
@@ -517,6 +530,13 @@
}
assertTrue(mWifiManager.isWifiEnabled());
+ // give the test a chance to autoconnect
+ Thread.sleep(DURATION);
+ if (mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) {
+ // this test requires a connectable network be configured
+ fail("This test requires a wifi network connection.");
+ }
+
// This will generate a distinct stack trace if the initial connection fails.
connectWifi();
@@ -698,4 +718,163 @@
// Passpoint build config |config_wifi_hotspot2_enabled| is disabled, so noop.
}
}
+
+ public 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(mLOHSLock);
+ synchronized (mLOHSLock) {
+ try {
+ mWifiManager.startLocalOnlyHotspot(callback, null);
+ // now wait for callback
+ mLOHSLock.wait(DURATION);
+ } catch (InterruptedException e) {
+ }
+ // check if we got the callback
+ assertTrue(callback.onStartedCalled);
+ assertNotNull(callback.reservation.getWifiConfiguration());
+ 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() {
+ // first check that softap mode is supported by the device
+ if (!mWifiManager.isPortableHotspotSupported()) {
+ return;
+ }
+
+ boolean wifiEnabled = mWifiManager.isWifiEnabled();
+
+ TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
+
+ // at this point, wifi should be off
+ assertFalse(mWifiManager.isWifiEnabled());
+
+ stopLocalOnlyHotspot(callback, wifiEnabled);
+ assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
+ }
+
+ /**
+ * Verify calls to setWifiEnabled from a non-settings app while softap mode is active do not
+ * exit softap mode.
+ *
+ * This test uses the LocalOnlyHotspot API to enter softap mode. This should also be true when
+ * tethering is started.
+ * Note: Location mode must be enabled for this test.
+ */
+ public void testSetWifiEnabledByAppDoesNotStopHotspot() {
+ // first check that softap mode is supported by the device
+ if (!mWifiManager.isPortableHotspotSupported()) {
+ return;
+ }
+
+ boolean wifiEnabled = mWifiManager.isWifiEnabled();
+
+ TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
+ // at this point, wifi should be off
+ assertFalse(mWifiManager.isWifiEnabled());
+
+ // now we should fail to turn on wifi
+ assertFalse(mWifiManager.setWifiEnabled(true));
+
+ stopLocalOnlyHotspot(callback, wifiEnabled);
+ 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() {
+ // first check that softap mode is supported by the device
+ if (!mWifiManager.isPortableHotspotSupported()) {
+ return;
+ }
+
+ boolean caughtException = false;
+
+ boolean wifiEnabled = mWifiManager.isWifiEnabled();
+
+ TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
+
+ // at this point, wifi should be off
+ assertFalse(mWifiManager.isWifiEnabled());
+
+ // now make a second request - this should fail.
+ TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLOHSLock);
+ try {
+ mWifiManager.startLocalOnlyHotspot(callback2, null);
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice");
+ caughtException = true;
+ }
+ assertTrue(caughtException);
+
+ stopLocalOnlyHotspot(callback, wifiEnabled);
+ assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
+ }
}