Merge "aaudio CTS: test functions after release()" into rvc-qpr-dev
diff --git a/apps/CtsVerifier/res/layout/nls_item.xml b/apps/CtsVerifier/res/layout/nls_item.xml
index f1a10bf..e80d333 100644
--- a/apps/CtsVerifier/res/layout/nls_item.xml
+++ b/apps/CtsVerifier/res/layout/nls_item.xml
@@ -14,41 +14,51 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <ImageView
- android:id="@+id/nls_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_marginTop="10dip"
- android:contentDescription="@string/pass_button_text"
- android:padding="10dip"
- android:src="@drawable/fs_indeterminate" />
-
- <TextView
- android:id="@+id/nls_instructions"
- style="@style/InstructionsSmallFont"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/nls_status"
- android:text="@string/nls_enable_service" />
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/nls_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="10dip"
+ android:contentDescription="@string/pass_button_text"
+ android:padding="10dip"
+ android:src="@drawable/fs_indeterminate" />
+
+ <TextView
+ android:id="@+id/nls_instructions"
+ style="@style/InstructionsSmallFont"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_toRightOf="@id/nls_status"
+ android:text="@string/nls_enable_service" />
+ </LinearLayout>
<Button
android:id="@+id/nls_action_button"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/nls_instructions"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
- android:layout_toRightOf="@id/nls_status"
android:onClick="actionPressed"
+ android:layout_gravity="center_horizontal"
android:text="@string/nls_start_settings" />
-</RelativeLayout>
\ No newline at end of file
+ <LinearLayout
+ android:id="@+id/feedback"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 74d50fb..899750a 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2185,6 +2185,9 @@
and disabled, and that once enabled the service is able to receive notifications and
dismiss them.
</string>
+ <string name="nls_anr">This test checks that notifications are not sent with content that is
+ too long. If this test causes the test app to ANR, the test has failed.
+ </string>
<string name="msg_extras_preserved">Check that Message extras Bundle was preserved.</string>
<string name="conversation_section_ordering">If this device supports conversation notifications,
and groups them into a separate section from alerting and silent non-conversation
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
index aa5e9c0..121534a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
@@ -257,8 +257,8 @@
return item;
}
- protected View createAutoItem(ViewGroup parent, int stringId) {
- View item = mInflater.inflate(R.layout.nls_item, parent, false);
+ protected ViewGroup createAutoItem(ViewGroup parent, int stringId) {
+ ViewGroup item = (ViewGroup) mInflater.inflate(R.layout.nls_item, parent, false);
TextView instructions = item.findViewById(R.id.nls_instructions);
instructions.setText(stringId);
View button = item.findViewById(R.id.nls_action_button);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index 12e2b93..31980af 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -51,7 +51,7 @@
public static final String JSON_STATS = "stats";
public static final String JSON_LAST_AUDIBLY_ALERTED = "last_audibly_alerted";
- ArrayList<String> mPosted = new ArrayList<String>();
+ ArrayList<StatusBarNotification> mPosted = new ArrayList<>();
ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
ArrayList<String> mRemoved = new ArrayList<String>();
@@ -77,6 +77,15 @@
return mNotifications.values();
}
+ protected StatusBarNotification getPosted(String tag) {
+ for (StatusBarNotification sbn : mPosted) {
+ if (sbn.getTag().equals(tag)) {
+ return sbn;
+ }
+ }
+ return null;
+ }
+
protected String getKeyForTag(String tag) {
return mNotificationKeys.get(tag);
}
@@ -149,7 +158,7 @@
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
if (!mTestPackages.contains(sbn.getPackageName())) { return; }
Log.d(TAG, "posted: " + sbn.getTag());
- mPosted.add(sbn.getTag());
+ mPosted.add(sbn);
mPostedNotifications.add(sbn.getNotification());
JSONObject notification = new JSONObject();
try {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 42ee9e1..1d704b0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -56,6 +56,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
import androidx.core.app.NotificationCompat;
@@ -117,6 +119,7 @@
tests.add(new IsEnabledTest());
tests.add(new ServiceStartedTest());
tests.add(new NotificationReceivedTest());
+ tests.add(new LongMessageTest());
tests.add(new DataIntactTest());
tests.add(new AudiblyAlertedTest());
tests.add(new DismissOneTest());
@@ -261,8 +264,73 @@
@Override
protected void test() {
- List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
- if (result.size() > 0 && result.contains(mTag1)) {
+ if (MockListener.getInstance().getPosted(mTag1) != null) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ }
+ }
+
+ private class LongMessageTest extends InteractiveTestCase {
+ private ViewGroup mParent;
+ @Override
+ protected View inflate(ViewGroup parent) {
+ mParent = createAutoItem(parent, R.string.nls_anr);
+ return mParent;
+ }
+
+ @Override
+ protected void setUp() {
+ createChannels();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 20000; i++) {
+ sb.append("\u2009\u200a" + "\u200E\u200F" + "stuff");
+ }
+ Notification.Builder builder = new Notification.Builder(
+ mContext, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(android.R.id.icon)
+ .setContentTitle("This is an long notification")
+ .setContentText("Innocuous content")
+ .setStyle(new Notification.MessagingStyle("Fake person")
+ .addMessage("hey how is it goin", 0, "Person 1")
+ .addMessage("hey", 0, "Person 1")
+ .addMessage("u there", 0, "Person 1")
+ .addMessage("how you like tHIS", 0, "Person 1")
+ .addMessage(sb.toString(), 0, "Person 1")
+ );
+ mTag1 = UUID.randomUUID().toString();
+ mId1 = NOTIFICATION_ID + 1;
+ mPackageString = "com.android.cts.verifier";
+ mNm.notify(mTag1, mId1, builder.build());
+ status = READY;
+ }
+
+ @Override
+ protected void tearDown() {
+ mNm.cancelAll();
+ MockListener.getInstance().resetData();
+ deleteChannels();
+ }
+
+ @Override
+ protected void test() {
+ StatusBarNotification sbn = MockListener.getInstance().getPosted(mTag1);
+ if (sbn == null) {
+ logFail();
+ status = FAIL;
+ } else {
+ ViewGroup parent = mParent.findViewById(R.id.feedback);
+ parent.setVisibility(View.VISIBLE);
+ final Notification.Builder recoveredBuilder = Notification.Builder.recoverBuilder(
+ NotificationListenerVerifierActivity.this,
+ sbn.getNotification());
+ RemoteViews rv = recoveredBuilder.createContentView();
+ View v = rv.apply(NotificationListenerVerifierActivity.this, parent);
+ parent.addView(v);
+ }
+ if (MockListener.getInstance().getPosted(mTag1) != null) {
status = PASS;
} else {
logFail();
@@ -985,8 +1053,7 @@
if (MockListener.getInstance() == null) {
status = PASS;
} else {
- List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
- if (result.size() == 0) {
+ if (MockListener.getInstance().mPosted.size() == 0) {
status = PASS;
} else {
logFail();
@@ -1157,8 +1224,7 @@
state = READY_TO_CHECK_FOR_UNSNOOZE;
}
} else {
- List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
- if (result.size() > 0 && result.contains(mTag1)) {
+ if (MockListener.getInstance().getPosted(mTag1) != null) {
status = PASS;
} else {
logFail();
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 41a05d5..b709d35 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -249,4 +249,11 @@
<option name="jar" value="CtsSecurityBulletinHostTestCases.jar" />
<option name="runtime-hint" value="18m26s" />
</test>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
+ <option name="src-dir" value="/sdcard/report-log-files/"/>
+ <option name="dest-dir" value="report-log-files/"/>
+ <option name="temp-dir" value="temp-report-logs/"/>
+ <option name="device-dir" value="true"/>
+ </target_preparer>
</configuration>
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 6d9454f..7b8fae0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -17,6 +17,9 @@
package android.security.cts;
import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.MetricsReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.NullOutputReceiver;
import com.android.ddmlib.CollectingOutputReceiver;
@@ -151,8 +154,30 @@
if (arguments == null) {
arguments = "";
}
- device.executeShellCommand(TMP_PATH + pocName + " " + arguments,
+
+ // since we have to return the exit status AND the poc stdout+stderr we redirect the exit
+ // status to a file temporarily
+ String exitStatusFilepath = TMP_PATH + "exit_status";
+ runCommandLine("rm " + exitStatusFilepath, device); // remove any old exit status
+ device.executeShellCommand(TMP_PATH + pocName + " " + arguments +
+ "; echo $? > " + exitStatusFilepath, // echo exit status to file
receiver, timeout, TimeUnit.SECONDS, 0);
+
+ // cat the exit status
+ String exitStatusString = runCommandLine("cat " + exitStatusFilepath, device).trim();
+
+ MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
+ reportLog.addValue("poc_name", pocName, ResultType.NEUTRAL, ResultUnit.NONE);
+ try {
+ int exitStatus = Integer.parseInt(exitStatusString);
+ reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
+ } catch (NumberFormatException e) {
+ // Getting the exit status is a bonus. We can continue without it.
+ CLog.w("Could not parse exit status to int: %s", exitStatusString);
+ }
+ reportLog.submit();
+
+ runCommandLine("rm " + exitStatusFilepath, device);
}
/**
@@ -307,15 +332,21 @@
*/
public static int runCommandGetExitCode(String cmd, ITestDevice device) throws Exception {
long time = System.currentTimeMillis();
- String exitStatus = runCommandLine(
+ String exitStatusString = runCommandLine(
"(" + cmd + ") > /dev/null 2>&1; echo $?", device).trim();
time = System.currentTimeMillis() - time;
+
try {
- return Integer.parseInt(exitStatus);
+ int exitStatus = Integer.parseInt(exitStatusString);
+ MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
+ reportLog.addValue("command", cmd, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit();
+ return exitStatus;
} catch (NumberFormatException e) {
throw new IllegalArgumentException(String.format(
"Could not get the exit status (%s) for '%s' (%d ms).",
- exitStatus, cmd, time));
+ exitStatusString, cmd, time));
}
}
@@ -362,13 +393,19 @@
long time = System.currentTimeMillis();
device.executeShellCommand(cmd, receiver, timeout, TimeUnit.SECONDS, 0);
time = System.currentTimeMillis() - time;
- String exitStatus = receiver.getOutput().trim();
+ String exitStatusString = receiver.getOutput().trim();
+
try {
- return Integer.parseInt(exitStatus);
+ int exitStatus = Integer.parseInt(exitStatusString);
+ MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
+ reportLog.addValue("poc_name", pocName, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit();
+ return exitStatus;
} catch (NumberFormatException e) {
throw new IllegalArgumentException(String.format(
"Could not get the exit status (%s) for '%s' (%d ms).",
- exitStatus, cmd, time));
+ exitStatusString, cmd, time));
}
}
@@ -572,6 +609,12 @@
JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
JSONArray securityCrashes = CrashUtils.matchSecurityCrashes(crashes, config);
+ MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
+ reportLog.addValue("all_crashes", crashes.toString(), ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue("security_crashes", securityCrashes.toString(),
+ ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit();
+
if (securityCrashes.length() == 0) {
return; // no security crashes detected
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 0df41b1..ec89b1672 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -16,6 +16,13 @@
package android.security.cts;
+import com.android.compatibility.common.util.MetricsReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -24,10 +31,14 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.ddmlib.Log;
+import org.junit.rules.TestName;
+import org.junit.Rule;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
+import java.util.Map;
+import java.util.HashMap;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.concurrent.Callable;
@@ -50,6 +61,12 @@
private HostsideOomCatcher oomCatcher = new HostsideOomCatcher(this);
private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
+ @Rule public TestName testName = new TestName();
+
+ private static Map<ITestDevice, IBuildInfo> sBuildInfo = new HashMap<>();
+ private static Map<ITestDevice, IAbi> sAbi = new HashMap<>();
+ private static Map<ITestDevice, String> sTestName = new HashMap<>();
+
/**
* Waits for device to be online, marks the most recent boottime of the device
*/
@@ -62,6 +79,9 @@
// Specifically time when app framework starts
oomCatcher.start();
+ sBuildInfo.put(getDevice(), getBuild());
+ sAbi.put(getDevice(), getAbi());
+ sTestName.put(getDevice(), testName.getMethodName());
}
/**
@@ -103,6 +123,18 @@
}
}
+ public static IBuildInfo getBuildInfo(ITestDevice device) {
+ return sBuildInfo.get(device);
+ }
+
+ public static IAbi getAbi(ITestDevice device) {
+ return sAbi.get(device);
+ }
+
+ public static String getTestName(ITestDevice device) {
+ return sTestName.get(device);
+ }
+
// TODO convert existing assertMatches*() to RegexUtils.assertMatches*()
// b/123237827
@Deprecated
@@ -190,7 +222,39 @@
* Check if a driver is present on a machine.
*/
protected boolean containsDriver(ITestDevice device, String driver) throws Exception {
- return AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0;
+ boolean containsDriver = AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0;
+
+ MetricsReportLog reportLog = buildMetricsReportLog(getDevice());
+ reportLog.addValue("path", driver, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue("exists", containsDriver, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit();
+
+ return containsDriver;
+ }
+
+ protected static MetricsReportLog buildMetricsReportLog(ITestDevice device) {
+ IBuildInfo buildInfo = getBuildInfo(device);
+ IAbi abi = getAbi(device);
+ String testName = getTestName(device);
+
+ StackTraceElement[] stacktraces = Thread.currentThread().getStackTrace();
+ int stackDepth = 2; // 0: getStackTrace(), 1: buildMetricsReportLog, 2: caller
+ String className = stacktraces[stackDepth].getClassName();
+ String methodName = stacktraces[stackDepth].getMethodName();
+ String classMethodName = String.format("%s#%s", className, methodName);
+
+ // The stream name must be snake_case or else json formatting breaks
+ String streamName = methodName.replaceAll("(\\p{Upper})", "_$1").toLowerCase();
+
+ MetricsReportLog reportLog = new MetricsReportLog(
+ buildInfo,
+ abi.getName(),
+ classMethodName,
+ "CtsSecurityBulletinHostTestCases",
+ streamName,
+ true);
+ reportLog.addValue("test_name", testName, ResultType.NEUTRAL, ResultUnit.NONE);
+ return reportLog;
}
private long getDeviceUptime() throws DeviceNotAvailableException {
diff --git a/libs/install/Android.bp b/libs/install/Android.bp
index 0e1ebb0..e7bf788 100644
--- a/libs/install/Android.bp
+++ b/libs/install/Android.bp
@@ -91,7 +91,7 @@
}
java_library {
- name: "cts-install-lib",
+ name: "cts-install-lib-java",
srcs: ["src/**/*.java"],
static_libs: ["androidx.test.rules", "compatibility-device-util-axt", "truth-prebuilt"],
sdk_version: "test_current",
@@ -110,3 +110,11 @@
":StagedInstallTestApexV3",
],
}
+
+android_library {
+ name: "cts-install-lib",
+ manifest: "AndroidManifest.xml",
+ static_libs: [
+ "cts-install-lib-java",
+ ],
+}
diff --git a/libs/install/AndroidManifest.xml b/libs/install/AndroidManifest.xml
new file mode 100644
index 0000000..e9f5b7d
--- /dev/null
+++ b/libs/install/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.install.lib"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <queries>
+ <package android:name="com.android.cts.install.lib.testapp.A"/>
+ <package android:name="com.android.cts.install.lib.testapp.B"/>
+ <package android:name="com.android.cts.install.lib.testapp.C"/>
+ </queries>
+
+ <uses-sdk android:minSdkVersion="8"/>
+</manifest>
diff --git a/libs/install/testapp/ACrashingV2.xml b/libs/install/testapp/ACrashingV2.xml
index 0ec90cf..338a5b9 100644
--- a/libs/install/testapp/ACrashingV2.xml
+++ b/libs/install/testapp/ACrashingV2.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A v2" android:forceQueryable="true">
+ <application android:label="Test App A v2">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.CrashingMainActivity">
diff --git a/libs/install/testapp/Av1.xml b/libs/install/testapp/Av1.xml
index 5b47699..e9714fc 100644
--- a/libs/install/testapp/Av1.xml
+++ b/libs/install/testapp/Av1.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A1" android:forceQueryable="true">
+ <application android:label="Test App A1">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Av2.xml b/libs/install/testapp/Av2.xml
index 9f2c21a..fd8afa0 100644
--- a/libs/install/testapp/Av2.xml
+++ b/libs/install/testapp/Av2.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A2" android:forceQueryable="true">
+ <application android:label="Test App A2">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Av3.xml b/libs/install/testapp/Av3.xml
index d86aebd..a7839e3 100644
--- a/libs/install/testapp/Av3.xml
+++ b/libs/install/testapp/Av3.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A3" android:forceQueryable="true">
+ <application android:label="Test App A3">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Bv1.xml b/libs/install/testapp/Bv1.xml
index f990713..403e7e2 100644
--- a/libs/install/testapp/Bv1.xml
+++ b/libs/install/testapp/Bv1.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App B1" android:forceQueryable="true">
+ <application android:label="Test App B1">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Bv2.xml b/libs/install/testapp/Bv2.xml
index 3bd7292..f030c3f 100644
--- a/libs/install/testapp/Bv2.xml
+++ b/libs/install/testapp/Bv2.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App B2" android:forceQueryable="true">
+ <application android:label="Test App B2">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Cv1.xml b/libs/install/testapp/Cv1.xml
index 32f6989..edb69f9 100644
--- a/libs/install/testapp/Cv1.xml
+++ b/libs/install/testapp/Cv1.xml
@@ -23,7 +23,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App C1" android:forceQueryable="true">
+ <application android:label="Test App C1">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/tests/tests/appenumeration/AndroidTest.xml b/tests/tests/appenumeration/AndroidTest.xml
index 6503bdb..26f6b90 100644
--- a/tests/tests/appenumeration/AndroidTest.xml
+++ b/tests/tests/appenumeration/AndroidTest.xml
@@ -26,7 +26,7 @@
<option name="force-queryable" value="false" />
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAppEnumerationTestCases.apk" />
- <option name="test-file-name" value="CtsAppEnumerationForceQueryable.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationForceQueryableNormalInstall.apk" />
<option name="test-file-name" value="CtsAppEnumerationFilters.apk" />
<option name="test-file-name" value="CtsAppEnumerationNoApi.apk" />
<option name="test-file-name" value="CtsAppEnumerationContactsActivityTarget.apk" />
@@ -61,6 +61,12 @@
<option name="test-file-name" value="CtsAppEnumerationWildcardBrowserActivitySource.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="force-queryable" value="true" />
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsAppEnumerationForceQueryable.apk" />
+ </target_preparer>
+
<!-- Create place to store apks -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/cts/appenumeration" />
diff --git a/tests/tests/appenumeration/app/target/Android.bp b/tests/tests/appenumeration/app/target/Android.bp
index 04ebc78..b3afe4b 100644
--- a/tests/tests/appenumeration/app/target/Android.bp
+++ b/tests/tests/appenumeration/app/target/Android.bp
@@ -27,6 +27,20 @@
}
android_test_helper_app {
+ name: "CtsAppEnumerationForceQueryableNormalInstall",
+ manifest: "AndroidManifest-forceQueryable-normalInstall.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
+
+android_test_helper_app {
name: "CtsAppEnumerationFilters",
manifest: "AndroidManifest-filters.xml",
defaults: ["cts_support_defaults"],
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable-normalInstall.xml b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable-normalInstall.xml
new file mode 100644
index 0000000..2918e37
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable-normalInstall.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.appenumeration.forcequeryable.normalinstall">
+ <application android:forceQueryable="true">
+ <!-- This app will not be a system app and should be installed as a normal app (not
+ forceQueryable) to ensure it's not visible by default -->
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml
index e6535b3..041d350 100644
--- a/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml
@@ -18,6 +18,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.appenumeration.forcequeryable">
<application android:forceQueryable="true">
+ <!-- This app will not be a system app and so must be installed as forceQueryable by the
+ test framework -->
<uses-library android:name="android.test.runner" />
</application>
</manifest>
diff --git a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
index 6fcba54..d7c8dae 100644
--- a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
+++ b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
@@ -78,8 +78,13 @@
public static final String TARGET_SHARED_USER = PKG_BASE + "noapi.shareduid";
/** A package that exposes itself via various intent filters (activities, services, etc.) */
public static final String TARGET_FILTERS = PKG_BASE + "filters";
- /** A package that declares itself force queryable, making it visible to all other packages */
+ /** A package that declares itself force queryable, making it visible to all other packages.
+ * This is installed as forceQueryable as non-system apps cannot declare themselves as such. */
public static final String TARGET_FORCEQUERYABLE = PKG_BASE + "forcequeryable";
+ /** A package that declares itself force queryable, but is installed normally making it not
+ * visible to other packages */
+ public static final String TARGET_FORCEQUERYABLE_NORMAL =
+ PKG_BASE + "forcequeryable.normalinstall";
/** A package with no published API and so isn't queryable by anything but package name */
public static final String TARGET_NO_API = PKG_BASE + "noapi";
/** A package that offers an activity used for opening / editing file types */
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index d95970b..cfd12a2 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -66,6 +66,7 @@
import static android.appenumeration.cts.Constants.TARGET_FILTERS;
import static android.appenumeration.cts.Constants.TARGET_FILTERS_APK;
import static android.appenumeration.cts.Constants.TARGET_FORCEQUERYABLE;
+import static android.appenumeration.cts.Constants.TARGET_FORCEQUERYABLE_NORMAL;
import static android.appenumeration.cts.Constants.TARGET_NO_API;
import static android.appenumeration.cts.Constants.TARGET_SHARE;
import static android.appenumeration.cts.Constants.TARGET_SHARED_USER;
@@ -177,6 +178,15 @@
}
@Test
+ public void all_cannotSeeForceQueryableInstalledNormally() throws Exception {
+ assertNotVisible(QUERIES_NOTHING, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_ACTIVITY_ACTION, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_SERVICE_ACTION, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_PROVIDER_AUTH, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_PACKAGE, TARGET_FORCEQUERYABLE_NORMAL);
+ }
+
+ @Test
public void startExplicitly_canStartNonVisible() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_FILTERS);
startExplicitIntentViaComponent(QUERIES_NOTHING, TARGET_FILTERS);
diff --git a/tests/tests/os/src/android/os/cts/LocaleListTest.java b/tests/tests/os/src/android/os/cts/LocaleListTest.java
index 8eee8c6..3d05332 100644
--- a/tests/tests/os/src/android/os/cts/LocaleListTest.java
+++ b/tests/tests/os/src/android/os/cts/LocaleListTest.java
@@ -93,13 +93,9 @@
public void testRepeatedArguments() {
final Locale[] la = {Locale.US, Locale.US};
- LocaleList ll = null;
- try {
- ll = new LocaleList(la);
- fail("Initializing a LocaleList with an array containing duplicates should throw.");
- } catch (Throwable e) {
- assertEquals(IllegalArgumentException.class, e.getClass());
- }
+ LocaleList ll = new LocaleList(la);
+ assertEquals(1, ll.size());
+ assertEquals(Locale.US, ll.get(0));
}
public void testIndexOf() {
diff --git a/tests/tests/permission/Android.bp b/tests/tests/permission/Android.bp
index 376c579..6c42051 100644
--- a/tests/tests/permission/Android.bp
+++ b/tests/tests/permission/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "sts",
],
// Include both the 32 and 64 bit versions
compile_multilib: "both",
diff --git a/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java b/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java
index ee9359c..5043e15 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java
@@ -17,6 +17,7 @@
package android.telecom.cts;
import android.content.Intent;
+import android.os.Process;
import android.telecom.Call;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
@@ -29,6 +30,8 @@
TestUtils.InvokeCounter mShowMissedCallNotificationIntentCounter =
new TestUtils.InvokeCounter("ShowMissedCallNotificationIntent");
+ private static final String CMD_DEVICE_IDLE_TEMP_EXEMPTIONS = "cmd deviceidle tempwhitelist";
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -71,6 +74,15 @@
connection.setDisconnected(new DisconnectCause(DisconnectCause.MISSED));
connection.destroy();
mShowMissedCallNotificationIntentCounter.waitForCount(1);
+ assertTrue("After missing a call, if the default dialer is handling the missed call "
+ + "notification, then it must be in the temporary power exemption list.",
+ isOnTemporaryPowerExemption());
}
+ private boolean isOnTemporaryPowerExemption() throws Exception {
+ String exemptions = TestUtils.executeShellCommand(
+ getInstrumentation(), CMD_DEVICE_IDLE_TEMP_EXEMPTIONS);
+ // Just check that this process's UID is in the result.
+ return exemptions.contains(String.valueOf(Process.myUid()));
+ }
}