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()));
+    }
 }