Merge "TIF: Add test cases for DVR APIs"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 29f027e..e09cccd 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -4,6 +4,7 @@
 
 [Builtin Hooks Options]
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               hostsidetests
                tests/tests/binder_ndk
 
 [Hook Scripts]
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
index fbd7522..37df8ad 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
@@ -483,6 +483,7 @@
             CameraCharacteristics chars = (CameraCharacteristics) md;
             List<CameraCharacteristics.Key<?>> charsKeys = chars.getKeys();
             List<CaptureRequest.Key<?>> requestKeys = chars.getAvailableCaptureRequestKeys();
+            List<CaptureResult.Key<?>> resultKeys = chars.getAvailableCaptureResultKeys();
             Set<String> physicalCamIds = chars.getPhysicalCameraIds();
 
             try {
@@ -494,9 +495,14 @@
                 for (CaptureRequest.Key<?> k : requestKeys) {
                     reqKeysArr.put(k.getName());
                 }
+                JSONArray resKeysArr = new JSONArray();
+                for (CaptureResult.Key<?> k : resultKeys) {
+                    resKeysArr.put(k.getName());
+                }
                 // Avoid using the hidden metadata key name here to prevent confliction
                 jsonObj.put("camera.characteristics.keys", charKeysArr);
                 jsonObj.put("camera.characteristics.requestKeys", reqKeysArr);
+                jsonObj.put("camera.characteristics.resultKeys", resKeysArr);
 
                 if (!physicalCamIds.isEmpty()) {
                     JSONArray physCamIdsArr = new JSONArray();
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
index 9eb97c5..8b1e28c 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
@@ -45,6 +45,7 @@
     private static final String PERMISSION_PROTECTION = "protection_level";
     private static final String PERMISSION_PROTECTION_FLAGS = "protection_level_flags";
 
+    private static final int SYS_UID_MAX = 10000;
     private static final String HAS_SYSTEM_UID = "has_system_uid";
 
     private static final String SHARES_INSTALL_PERMISSION = "shares_install_packages_permission";
@@ -53,7 +54,6 @@
     @Override
     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
         final PackageManager pm = getContext().getPackageManager();
-        final ApplicationInfo system = pm.getApplicationInfo("android", 0);
 
         final List<PackageInfo> allPackages = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
 
@@ -92,7 +92,7 @@
                 store.addResult(MIN_SDK, appInfo.minSdkVersion);
                 store.addResult(TARGET_SDK, appInfo.targetSdkVersion);
 
-                store.addResult(HAS_SYSTEM_UID, appInfo.uid == system.uid);
+                store.addResult(HAS_SYSTEM_UID, appInfo.uid < SYS_UID_MAX);
 
                 final boolean canInstall = sharesUidWithPackageHolding(pm, appInfo.uid, INSTALL_PACKAGES_PERMISSION);
                 store.addResult(SHARES_INSTALL_PERMISSION, canInstall);
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java
index dc6f6e8..948baaf 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java
@@ -62,6 +62,21 @@
      *
      * @param <U> the type of the object against which the method is invoked.
      */
+    public interface ShellPermissionThrowableMethodHelper<T, U, E extends Throwable> {
+        /**
+         * Invokes the method against the target object.
+         *
+         * @param targetObject the object against which the method should be invoked.
+         * @return the result of the target method.
+         */
+        T callMethod(U targetObject) throws E;
+    }
+
+    /**
+     * Utility interface to invoke a method against the target object that may throw an Exception.
+     *
+     * @param <U> the type of the object against which the method is invoked.
+     */
     public interface ShellPermissionThrowableMethodHelperNoReturn<U, E extends Throwable> {
         /**
          * Invokes the method against the target object.
@@ -184,6 +199,27 @@
     }
 
     /**
+     * Invokes the specified method on the targetObject as the shell user with only the subset of
+     * permissions specified. The method can be invoked as follows:
+     *
+     * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mRcsUceAdapter,
+     *        (m) -> RcsUceAdapter::getUcePublishState, ImsException.class,
+     *                     "android.permission.READ_PRIVILEGED_PHONE_STATE")}
+     */
+    public static <T, U, E extends Throwable> T invokeThrowableMethodWithShellPermissions(
+            U targetObject, ShellPermissionThrowableMethodHelper<T, U, E> methodHelper,
+            Class<E> clazz, String... permissions) throws E {
+        final UiAutomation uiAutomation =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity(permissions);
+            return methodHelper.callMethod(targetObject);
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
      * Invokes the specified method on the targetObject as the shell user for only the permissions
      * specified. The method can be invoked as follows:
      *
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java
index 0907d30..6e48bcc 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java
@@ -50,10 +50,10 @@
             "9A:4B:85:34:44:86:EC:F5:1F:F8:05:EB:9D:23:17:97:79:BE:B7:EC:81:91:93:5A:CA:67:F0"
                     + ":F4:09:02:52:97"),
     // Consistency
-    TZDATA("com.google.android.tzdata2",
+    TZDATA2("com.google.android.tzdata2",
             true, ModuleType.APEX,
-            "55:93:DD:78:CB:26:EC:9B:00:59:2A:6A:F5:94:E4:16:1F:FD:B5:E9:F3:71:A7:43:54:5F:93"
-                    + ":F2:A0:F6:53:89"),
+            "48:F3:A2:98:76:1B:6D:46:75:7C:EE:62:43:66:6A:25:B9:15:B9:42:18:A6:C2:82:72:99:BE"
+                    + ":DA:C9:92:AB:E7"),
     NETWORK_STACK("com.google.android.networkstack",
             true, ModuleType.APK,
             "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index ec3594e..5372bc1 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -83,8 +83,8 @@
             "com.android.cts.mediastorageapp", MEDIA_CLAZZ);
     private static final Config MEDIA_28 = new Config("CtsMediaStorageApp28.apk",
             "com.android.cts.mediastorageapp28", MEDIA_CLAZZ);
-    private static final Config MEDIA_FULL = new Config("CtsMediaStorageAppFull.apk",
-            "com.android.cts.mediastorageappfull", MEDIA_CLAZZ);
+    private static final Config MEDIA_29 = new Config("CtsMediaStorageApp29.apk",
+            "com.android.cts.mediastorageapp29", MEDIA_CLAZZ);
 
     private static final String PERM_READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
     private static final String PERM_WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
@@ -478,26 +478,26 @@
         doMediaSandboxed(MEDIA_28, false);
     }
     @Test
-    public void testMediaSandboxedFull() throws Exception {
-        doMediaSandboxed(MEDIA_FULL, false);
+    public void testMediaSandboxed29() throws Exception {
+        doMediaSandboxed(MEDIA_29, false);
     }
 
     private void doMediaSandboxed(Config config, boolean sandboxed) throws Exception {
         installPackage(config.apk);
-        installPackage(MEDIA_FULL.apk);
+        installPackage(MEDIA_29.apk);
         for (int user : mUsers) {
             updatePermissions(config.pkg, user, new String[] {
                     PERM_READ_EXTERNAL_STORAGE,
                     PERM_WRITE_EXTERNAL_STORAGE,
             }, true);
-            updatePermissions(MEDIA_FULL.pkg, user, new String[] {
+            updatePermissions(MEDIA_29.pkg, user, new String[] {
                     PERM_READ_EXTERNAL_STORAGE,
                     PERM_WRITE_EXTERNAL_STORAGE,
             }, true);
 
-            // Create the files needed for the test from MEDIA_FULL pkg since shell
+            // Create the files needed for the test from MEDIA_29 pkg since shell
             // can't access secondary user's storage.
-            runDeviceTests(MEDIA_FULL.pkg, MEDIA_FULL.clazz, "testStageFiles", user);
+            runDeviceTests(MEDIA_29.pkg, MEDIA_29.clazz, "testStageFiles", user);
 
             if (sandboxed) {
                 runDeviceTests(config.pkg, config.clazz, "testSandboxed", user);
@@ -505,7 +505,7 @@
                 runDeviceTests(config.pkg, config.clazz, "testNotSandboxed", user);
             }
 
-            runDeviceTests(MEDIA_FULL.pkg, MEDIA_FULL.clazz, "testClearFiles", user);
+            runDeviceTests(MEDIA_29.pkg, MEDIA_29.clazz, "testClearFiles", user);
         }
     }
 
@@ -518,8 +518,8 @@
         doMediaNone(MEDIA_28);
     }
     @Test
-    public void testMediaNoneFull() throws Exception {
-        doMediaNone(MEDIA_FULL);
+    public void testMediaNone29() throws Exception {
+        doMediaNone(MEDIA_29);
     }
 
     private void doMediaNone(Config config) throws Exception {
@@ -543,8 +543,8 @@
         doMediaRead(MEDIA_28);
     }
     @Test
-    public void testMediaReadFull() throws Exception {
-        doMediaRead(MEDIA_FULL);
+    public void testMediaRead29() throws Exception {
+        doMediaRead(MEDIA_29);
     }
 
     private void doMediaRead(Config config) throws Exception {
@@ -570,8 +570,8 @@
         doMediaWrite(MEDIA_28);
     }
     @Test
-    public void testMediaWriteFull() throws Exception {
-        doMediaWrite(MEDIA_FULL);
+    public void testMediaWrite29() throws Exception {
+        doMediaWrite(MEDIA_29);
     }
 
     private void doMediaWrite(Config config) throws Exception {
@@ -595,8 +595,8 @@
         doMediaEscalation(MEDIA_28);
     }
     @Test
-    public void testMediaEscalationFull() throws Exception {
-        doMediaEscalation(MEDIA_FULL);
+    public void testMediaEscalation29() throws Exception {
+        doMediaEscalation(MEDIA_29);
     }
 
     private void doMediaEscalation(Config config) throws Exception {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 2b45911..7130c14 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -23,6 +23,7 @@
 import static org.hamcrest.CoreMatchers.containsString;
 
 import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.FlakyTest;
 import android.platform.test.annotations.Presubmit;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
@@ -501,12 +502,14 @@
                 "reviewPermissionWhenServiceIsBound");
     }
 
+    @FlakyTest
     public void testGrantDialogToSettingsNoOp() throws Exception {
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), true, false));
         runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest29",
                 "openSettingsFromGrantNoOp");
     }
 
+    @FlakyTest
     public void testGrantDialogToSettingsDowngrade() throws Exception {
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
         runThrowingTest("com.android.cts.usepermission.UsePermissionTest29",
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp
index 22cc2f4..1f2b551 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp
@@ -52,7 +52,7 @@
 }
 
 android_test_helper_app {
-    name: "CtsMediaStorageAppFull",
+    name: "CtsMediaStorageApp29",
     defaults: ["cts_support_defaults"],
     sdk_version: "test_current",
     static_libs: [
@@ -68,5 +68,5 @@
         "vts",
         "general-tests",
     ],
-    manifest: "AndroidManifestFull.xml",
+    manifest: "AndroidManifest29.xml",
 }
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifestFull.xml b/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest29.xml
similarity index 88%
rename from hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifestFull.xml
rename to hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest29.xml
index 83b15c3..a73ab0e 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifestFull.xml
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest29.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-       package="com.android.cts.mediastorageappfull">
+       package="com.android.cts.mediastorageapp29">
 
     <application
         android:requestLegacyExternalStorage="true">
@@ -33,9 +33,12 @@
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.cts.mediastorageappfull" />
+        android:targetPackage="com.android.cts.mediastorageapp29" />
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
+    <uses-sdk
+        android:minSdkVersion="29"
+        android:targetSdkVersion="29" />
 </manifest>
diff --git a/hostsidetests/blobstore/Android.bp b/hostsidetests/blobstore/Android.bp
new file mode 100644
index 0000000..398aff8
--- /dev/null
+++ b/hostsidetests/blobstore/Android.bp
@@ -0,0 +1,52 @@
+// 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.
+
+java_test_host {
+    name: "CtsBlobStoreHostTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "tools-common-prebuilt",
+        "cts-tradefed",
+        "tradefed",
+        "truth-prebuilt"
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests"
+    ]
+}
+
+android_test_helper_app {
+  name: "CtsBlobStoreHelperApp",
+  srcs:  ["test-apps/BlobStoreHelperApp/src/**/*.java"],
+  static_libs: [
+      "compatibility-device-util-axt",
+      "androidx.test.ext.junit",
+      "androidx.test.rules",
+      "BlobStoreTestUtils",
+      "truth-prebuilt",
+      "testng",
+  ],
+  manifest : "test-apps/BlobStoreHelperApp/AndroidManifest.xml",
+  platform_apis: true,
+  // Tag this module as a cts test artifact
+  test_suites: [
+    "cts",
+    "vts",
+    "general-tests"
+  ]
+}
diff --git a/tests/tests/rcs/AndroidTest.xml b/hostsidetests/blobstore/AndroidTest.xml
similarity index 72%
rename from tests/tests/rcs/AndroidTest.xml
rename to hostsidetests/blobstore/AndroidTest.xml
index b51fd84..eaa301d 100644
--- a/tests/tests/rcs/AndroidTest.xml
+++ b/hostsidetests/blobstore/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
+<!-- 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.
@@ -13,22 +13,18 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for RCS test cases">
+<configuration description="Config for the CTS BlobStore host tests">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
-
-    <!-- RCS functionality depends on SMS permissions not available to instant apps. -->
+    <!-- Instant apps can't access BlobStoreManager -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
-
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsRcsTestCases.apk" />
-    </target_preparer>
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.telephony.ims.cts" />
-        <option name="hidden-api-checks" value="false"/>
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="jar" value="CtsBlobStoreHostTestCases.jar" />
     </test>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="test-file-name" value="CtsBlobStoreHelperApp.apk" />
+        <option name="cleanup-apks" value="true" />
+    </target_preparer>
 </configuration>
diff --git a/hostsidetests/blobstore/OWNERS b/hostsidetests/blobstore/OWNERS
new file mode 100644
index 0000000..16b25bb
--- /dev/null
+++ b/hostsidetests/blobstore/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+include platform/frameworks/base:apex/blobstore/OWNERS
diff --git a/hostsidetests/blobstore/TEST_MAPPING b/hostsidetests/blobstore/TEST_MAPPING
new file mode 100644
index 0000000..0305e17
--- /dev/null
+++ b/hostsidetests/blobstore/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsBlobStoreHostTestCases"
+    }
+  ]
+}
diff --git a/hostsidetests/blobstore/src/com/android/cts/host/blob/BaseBlobStoreHostTest.java b/hostsidetests/blobstore/src/com/android/cts/host/blob/BaseBlobStoreHostTest.java
new file mode 100644
index 0000000..9e3701d
--- /dev/null
+++ b/hostsidetests/blobstore/src/com/android/cts/host/blob/BaseBlobStoreHostTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 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 com.android.cts.host.blob;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
+import com.android.tradefed.util.Pair;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+abstract class BaseBlobStoreHostTest extends BaseHostJUnit4Test {
+    private static final long TIMEOUT_BOOT_COMPLETE_MS = 120_000;
+
+    protected static final String KEY_SESSION_ID = "session";
+
+    protected static final String KEY_DIGEST = "digest";
+    protected static final String KEY_EXPIRY = "expiry";
+    protected static final String KEY_LABEL = "label";
+    protected static final String KEY_TAG = "tag";
+
+    protected static final String KEY_ALLOW_PUBLIC = "public";
+
+    protected void runDeviceTest(String testPkg, String testClass, String testMethod)
+            throws Exception {
+        runDeviceTest(testPkg, testClass, testMethod, null);
+    }
+
+    protected void runDeviceTestAsUser(String testPkg, String testClass, String testMethod,
+            int userId) throws Exception {
+        runDeviceTestAsUser(testPkg, testClass, testMethod, null, userId);
+    }
+
+    protected void runDeviceTest(String testPkg, String testClass, String testMethod,
+            Map<String, String> instrumentationArgs) throws Exception {
+        runDeviceTestAsUser(testPkg, testClass, testMethod, instrumentationArgs, -1);
+    }
+
+    protected void runDeviceTestAsUser(String testPkg, String testClass, String testMethod,
+            Map<String, String> instrumentationArgs, int userId) throws Exception {
+        final DeviceTestRunOptions deviceTestRunOptions = new DeviceTestRunOptions(testPkg)
+                .setTestClassName(testClass)
+                .setTestMethodName(testMethod);
+        if (userId != -1) {
+            deviceTestRunOptions.setUserId(userId);
+        }
+        if (instrumentationArgs != null) {
+            for (Map.Entry<String, String> entry : instrumentationArgs.entrySet()) {
+                deviceTestRunOptions.addInstrumentationArg(entry.getKey(), entry.getValue());
+            }
+        }
+        assertWithMessage(testMethod + " failed").that(
+                runDeviceTests(deviceTestRunOptions)).isTrue();
+    }
+
+    protected void rebootAndWaitUntilReady() throws Exception {
+        // TODO: use rebootUserspace()
+        getDevice().rebootUntilOnline();
+        assertWithMessage("Timed out waiting for device to boot").that(
+                getDevice().waitForBootComplete(TIMEOUT_BOOT_COMPLETE_MS)).isTrue();
+    }
+
+    protected boolean isMultiUserSupported() throws Exception {
+        return getDevice().isMultiUserSupported();
+    }
+
+    protected Map<String, String> createArgsFromLastTestRun() {
+        final Map<String, String> args = new HashMap<>();
+        for (String key : new String[] {
+                KEY_SESSION_ID,
+                KEY_DIGEST,
+                KEY_EXPIRY,
+                KEY_LABEL,
+                KEY_TAG
+        }) {
+            final String value = getLastDeviceRunResults().getRunMetrics().get(key);
+            if (value != null) {
+                args.put(key, value);
+            }
+        }
+        return args;
+    }
+
+    protected Map<String, String> createArgs(Pair<String, String>... keyValues) {
+        return Arrays.stream(keyValues).collect(Collectors.toMap(p -> p.first, p -> p.second));
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/blobstore/src/com/android/cts/host/blob/BlobStoreMultiUserTest.java b/hostsidetests/blobstore/src/com/android/cts/host/blob/BlobStoreMultiUserTest.java
new file mode 100644
index 0000000..9f58c3e
--- /dev/null
+++ b/hostsidetests/blobstore/src/com/android/cts/host/blob/BlobStoreMultiUserTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+package com.android.cts.host.blob;
+
+import static org.junit.Assume.assumeTrue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.util.Pair;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class BlobStoreMultiUserTest extends BaseBlobStoreHostTest {
+    private static final String TARGET_APK = "CtsBlobStoreHelperApp.apk";
+    private static final String TARGET_PKG = "com.android.cts.blob.helper";
+    private static final String TEST_CLASS = TARGET_PKG + ".DataCleanupTest";
+
+    private int mPrimaryUserId;
+    private int mSecondaryUserId;
+
+    @Before
+    public void setUp() throws Exception {
+        assumeTrue("Multi-user is not supported on this device",
+                isMultiUserSupported());
+
+        mPrimaryUserId = getDevice().getPrimaryUserId();
+        mSecondaryUserId = getDevice().createUser("Test_User");
+        assertThat(getDevice().startUser(mSecondaryUserId)).isTrue();
+
+        installPackageAsUser(TARGET_APK, true /* grantPermissions */, mPrimaryUserId);
+        installPackageAsUser(TARGET_APK, true /* grantPermissions */, mSecondaryUserId);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mSecondaryUserId > 0) {
+            getDevice().removeUser(mSecondaryUserId);
+        }
+    }
+
+    @Test
+    public void testCreateAndOpenSession() throws Exception {
+        // Create a session.
+        runDeviceTestAsUser(TARGET_PKG, TEST_CLASS, "testCreateSession",
+                mPrimaryUserId);
+        final Map<String, String> args = createArgsFromLastTestRun();
+        // Verify that previously created session can be accessed.
+        runDeviceTestAsUser(TARGET_PKG, TEST_CLASS, "testOpenSession", args,
+                mPrimaryUserId);
+        // verify that previously created session cannot be accessed from another user.
+        runDeviceTestAsUser(TARGET_PKG, TEST_CLASS, "testOpenSession_shouldThrow", args,
+                mSecondaryUserId);
+    }
+
+    @Test
+    public void testCommitAndOpenBlob() throws Exception {
+        Map<String, String> args = createArgs(Pair.create(KEY_ALLOW_PUBLIC, String.valueOf(1)));
+        // Commit a blob.
+        runDeviceTestAsUser(TARGET_PKG, TEST_CLASS, "testCommitBlob", args,
+                mPrimaryUserId);
+        args = createArgsFromLastTestRun();
+        // Verify that previously committed blob can be accessed.
+        runDeviceTestAsUser(TARGET_PKG, TEST_CLASS, "testOpenBlob", args,
+                mPrimaryUserId);
+        // Verify that previously committed blob cannot be access from another user.
+        runDeviceTestAsUser(TARGET_PKG, TEST_CLASS, "testOpenBlob_shouldThrow", args,
+                mSecondaryUserId);
+    }
+}
diff --git a/hostsidetests/blobstore/src/com/android/cts/host/blob/DataCleanupTest.java b/hostsidetests/blobstore/src/com/android/cts/host/blob/DataCleanupTest.java
new file mode 100644
index 0000000..8a3efc8
--- /dev/null
+++ b/hostsidetests/blobstore/src/com/android/cts/host/blob/DataCleanupTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+package com.android.cts.host.blob;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class DataCleanupTest extends BaseBlobStoreHostTest {
+    private static final String TARGET_APK = "CtsBlobStoreHelperApp.apk";
+    private static final String TARGET_PKG = "com.android.cts.blob.helper";
+    private static final String TEST_CLASS = TARGET_PKG + ".DataCleanupTest";
+
+    @Test
+    public void testPackageUninstall_openSession() throws Exception {
+        installPackage(TARGET_APK);
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCreateSession");
+        final Map<String, String> args = createArgsFromLastTestRun();
+        // Verify that previously created session can be accessed.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenSession", args);
+        uninstallPackage(TARGET_PKG);
+        installPackage(TARGET_APK);
+        // Verify that the new package cannot access the session.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenSession_shouldThrow", args);
+    }
+
+    @Test
+    public void testPackageUninstall_openBlob() throws Exception {
+        installPackage(TARGET_APK);
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCommitBlob");
+        final Map<String, String> args = createArgsFromLastTestRun();
+        // Verify that previously committed blob can be accessed.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenBlob", args);
+        uninstallPackage(TARGET_PKG);
+        installPackage(TARGET_APK);
+        // Verify that the new package cannot access the blob.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenBlob_shouldThrow", args);
+    }
+
+    @Test
+    public void testPackageUninstallAndReboot_openSession() throws Exception {
+        installPackage(TARGET_APK);
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCreateSession");
+        final Map<String, String> args = createArgsFromLastTestRun();
+        // Verify that previously created session can be accessed.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenSession", args);
+        uninstallPackage(TARGET_PKG);
+        // Reboot the device.
+        rebootAndWaitUntilReady();
+        installPackage(TARGET_APK);
+        // Verify that the new package cannot access the session.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenSession_shouldThrow", args);
+    }
+
+    @Test
+    public void testPackageUninstallAndReboot_openBlob() throws Exception {
+        installPackage(TARGET_APK);
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCommitBlob");
+        final Map<String, String> args = createArgsFromLastTestRun();
+        // Verify that previously committed blob can be accessed.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenBlob", args);
+        uninstallPackage(TARGET_PKG);
+        // Reboot the device.
+        rebootAndWaitUntilReady();
+        installPackage(TARGET_APK);
+        // Verify that the new package cannot access the blob.
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenBlob_shouldThrow", args);
+    }
+}
diff --git a/hostsidetests/blobstore/src/com/android/cts/host/blob/DataPersistenceTest.java b/hostsidetests/blobstore/src/com/android/cts/host/blob/DataPersistenceTest.java
new file mode 100644
index 0000000..39f9b32
--- /dev/null
+++ b/hostsidetests/blobstore/src/com/android/cts/host/blob/DataPersistenceTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package com.android.cts.host.blob;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class DataPersistenceTest extends BaseBlobStoreHostTest {
+    private static final String TARGET_APK = "CtsBlobStoreHelperApp.apk";
+    private static final String TARGET_PKG = "com.android.cts.blob.helper";
+    private static final String TEST_CLASS = TARGET_PKG + ".DataPersistenceTest";
+
+    @Test
+    public void testDataIsPersistedAcrossReboot() throws Exception {
+        installPackage(TARGET_APK);
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCreateSession");
+        rebootAndWaitUntilReady();
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenSessionAndWrite");
+        rebootAndWaitUntilReady();
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCommitSession");
+        rebootAndWaitUntilReady();
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenBlob");
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/AndroidManifest.xml b/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/AndroidManifest.xml
new file mode 100644
index 0000000..a649209
--- /dev/null
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?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.blob.helper">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+            android:name="androidx.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.cts.blob.helper"  />
+</manifest>
\ No newline at end of file
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/src/com/android/cts/blob/helper/DataCleanupTest.java b/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/src/com/android/cts/blob/helper/DataCleanupTest.java
new file mode 100644
index 0000000..f4a1f1c
--- /dev/null
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/src/com/android/cts/blob/helper/DataCleanupTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+package com.android.cts.blob.helper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.fail;
+
+import android.app.Instrumentation;
+import android.app.blob.BlobHandle;
+import android.app.blob.BlobStoreManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+import com.android.cts.blob.DummyBlobData;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Base64;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+@RunWith(AndroidJUnit4.class)
+public class DataCleanupTest {
+    private static final long TIMEOUT_COMMIT_CALLBACK_MS = 5_000;
+
+    private static final long PARTIAL_FILE_LENGTH_BYTES = 2002;
+
+    private static final String KEY_SESSION_ID = "session";
+
+    private static final String KEY_DIGEST = "digest";
+    private static final String KEY_EXPIRY = "expiry";
+    private static final String KEY_LABEL = "label";
+    private static final String KEY_TAG = "tag";
+
+    private static final String KEY_ALLOW_PUBLIC = "public";
+
+    private Context mContext;
+    private Instrumentation mInstrumentation;
+    private BlobStoreManager mBlobStoreManager;
+    private Random mRandom;
+
+    @Before
+    public void setUp() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getContext();
+        mBlobStoreManager = (BlobStoreManager) mContext.getSystemService(
+                Context.BLOB_STORE_SERVICE);
+        mRandom = new Random(24 /* seed */);
+    }
+
+    @Test
+    public void testCreateSession() throws Exception {
+        final DummyBlobData blobData = new DummyBlobData(mContext, mRandom, "test_data_blob");
+        blobData.prepare();
+
+        final long sessionId = createSession(blobData.getBlobHandle());
+        assertThat(sessionId).isGreaterThan(0L);
+        try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+            blobData.writeToSession(session, 0, PARTIAL_FILE_LENGTH_BYTES);
+        }
+        addSessionIdToResults(sessionId);
+    }
+
+    @Test
+    public void testOpenSession() throws Exception {
+        final long sessionId = getSessionIdFromArgs();
+        try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+            assertThat(session.getSize()).isEqualTo(PARTIAL_FILE_LENGTH_BYTES);
+        }
+    }
+
+    @Test
+    public void testOpenSession_shouldThrow() throws Exception {
+        final long sessionId = getSessionIdFromArgs();
+        try {
+            mBlobStoreManager.openSession(sessionId);
+            fail("Should throw");
+        } catch (SecurityException e) {
+            // expected
+        }
+        assertThrows(SecurityException.class,
+                () -> mBlobStoreManager.openSession(sessionId));
+    }
+
+    @Test
+    public void testCommitBlob() throws Exception {
+        final DummyBlobData blobData = new DummyBlobData(mContext, mRandom,
+                "test_data_blob", "test_data_blob");
+        blobData.prepare();
+
+        final long sessionId = createSession(blobData.getBlobHandle());
+        assertThat(sessionId).isGreaterThan(0L);
+        try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+            blobData.writeToSession(session);
+            if (getShouldAllowPublicFromArgs()) {
+                session.allowPublicAccess();
+            }
+            final CompletableFuture<Integer> callback = new CompletableFuture<>();
+            session.commit(mContext.getMainExecutor(), callback::complete);
+            assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_MS, TimeUnit.MILLISECONDS))
+                    .isEqualTo(0);
+        }
+        addBlobHandleToResults(blobData.getBlobHandle());
+    }
+
+    @Test
+    public void testOpenBlob() throws Exception {
+        final BlobHandle blobHandle = getBlobHandleFromArgs();
+        try (ParcelFileDescriptor pfd = mBlobStoreManager.openBlob(blobHandle)) {
+            assertThat(pfd).isNotNull();
+        }
+    }
+
+    @Test
+    public void testOpenBlob_shouldThrow() throws Exception {
+        final BlobHandle blobHandle = getBlobHandleFromArgs();
+        assertThrows(SecurityException.class,
+                () -> mBlobStoreManager.openBlob(blobHandle));
+    }
+
+    private long createSession(BlobHandle blobHandle) throws Exception {
+        final long sessionId = mBlobStoreManager.createSession(blobHandle);
+        return sessionId;
+    }
+
+    private void addSessionIdToResults(long sessionId) {
+        final Bundle results = new Bundle();
+        results.putLong(KEY_SESSION_ID, sessionId);
+        mInstrumentation.addResults(results);
+    }
+
+    private long getSessionIdFromArgs() {
+        final Bundle args = InstrumentationRegistry.getArguments();
+        return Long.parseLong(args.getString(KEY_SESSION_ID));
+    }
+
+    private void addBlobHandleToResults(BlobHandle blobHandle) {
+        final Bundle results = new Bundle();
+        results.putString(KEY_DIGEST,
+                Base64.getEncoder().encodeToString(blobHandle.getSha256Digest()));
+        results.putLong(KEY_EXPIRY, blobHandle.getExpiryTimeMillis());
+        results.putCharSequence(KEY_LABEL, blobHandle.getLabel().toString());
+        results.putString(KEY_TAG, blobHandle.getTag());
+        mInstrumentation.addResults(results);
+    }
+
+    private BlobHandle getBlobHandleFromArgs() {
+        final Bundle args = InstrumentationRegistry.getArguments();
+        final byte[] digest = Base64.getDecoder().decode(args.getString(KEY_DIGEST));
+        final CharSequence label = args.getString(KEY_LABEL);
+        final long expiryTimeMillis = Long.parseLong(args.getString(KEY_EXPIRY));
+        final String tag = args.getString(KEY_TAG);
+        return BlobHandle.createWithSha256(digest, label, expiryTimeMillis, tag);
+    }
+
+    private boolean getShouldAllowPublicFromArgs() {
+        final Bundle args = InstrumentationRegistry.getArguments();
+        return "1".equals(args.getString(KEY_ALLOW_PUBLIC));
+    }
+}
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/src/com/android/cts/blob/helper/DataPersistenceTest.java b/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/src/com/android/cts/blob/helper/DataPersistenceTest.java
new file mode 100644
index 0000000..a9bf207
--- /dev/null
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHelperApp/src/com/android/cts/blob/helper/DataPersistenceTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+package com.android.cts.blob.helper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.blob.BlobHandle;
+import android.app.blob.BlobStoreManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.ParcelFileDescriptor;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.cts.blob.DummyBlobData;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Base64;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+@RunWith(AndroidJUnit4.class)
+public class DataPersistenceTest {
+
+    private static final String KEY_SESSION_ID = "id";
+    private static final String KEY_DIGEST = "digest";
+    private static final String KEY_LABEL = "label";
+    private static final String KEY_EXPIRY = "expiry";
+    private static final String KEY_TAG = "tag";
+
+    private static final long PARTIAL_FILE_LENGTH_BYTES = 2002;
+    private static final long TIMEOUT_WAIT_FOR_IDLE_MS = 2_000;
+    private static final long TIMEOUT_COMMIT_CALLBACK_MS = 5_000;
+
+    private Context mContext;
+    private BlobStoreManager mBlobStoreManager;
+    private Random mRandom;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mBlobStoreManager = (BlobStoreManager) mContext.getSystemService(
+                Context.BLOB_STORE_SERVICE);
+        mRandom = new Random(22 /* seed */);
+    }
+
+    @Test
+    public void testCreateSession() throws Exception {
+        final DummyBlobData blobData = new DummyBlobData(mContext, mRandom, "test_data_blob");
+        blobData.prepare();
+
+        final long sessionId = createSession(blobData.getBlobHandle());
+        assertThat(sessionId).isGreaterThan(0L);
+        try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+            blobData.writeToSession(session, 0, PARTIAL_FILE_LENGTH_BYTES);
+        }
+        writeSessionIdToDisk(sessionId);
+        writeBlobHandleToDisk(blobData.getBlobHandle());
+
+        ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mBlobStoreManager,
+                (blobStoreManager) -> blobStoreManager.waitForIdle(TIMEOUT_WAIT_FOR_IDLE_MS),
+                Exception.class, android.Manifest.permission.DUMP);
+    }
+
+    @Test
+    public void testOpenSessionAndWrite() throws Exception {
+        final long sessionId = readSessionIdFromDisk();
+        final DummyBlobData blobData = new DummyBlobData(mContext, mRandom, "test_data_blob");
+        try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+            assertThat(session.getSize()).isEqualTo(PARTIAL_FILE_LENGTH_BYTES);
+            blobData.writeToSession(session, PARTIAL_FILE_LENGTH_BYTES,
+                    blobData.getFileSize() - PARTIAL_FILE_LENGTH_BYTES);
+        }
+    }
+
+    @Test
+    public void testCommitSession() throws Exception {
+        final long sessionId = readSessionIdFromDisk();
+        try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+            final CompletableFuture<Integer> callback = new CompletableFuture<>();
+            session.commit(mContext.getMainExecutor(), callback::complete);
+            assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_MS, TimeUnit.MILLISECONDS))
+                    .isEqualTo(0);
+        }
+    }
+
+    @Test
+    public void testOpenBlob() throws Exception {
+        final BlobHandle blobHandle = readBlobHandleFromDisk();
+        try (ParcelFileDescriptor pfd = mBlobStoreManager.openBlob(blobHandle)) {
+            assertThat(pfd).isNotNull();
+        }
+    }
+
+    private long createSession(BlobHandle blobHandle) throws Exception {
+        final long sessionId = mBlobStoreManager.createSession(blobHandle);
+        return sessionId;
+    }
+
+    private void writeSessionIdToDisk(long sessionId) {
+        final SharedPreferences sharedPref = getSharedPreferences();
+        assertThat(sharedPref.edit().putLong(KEY_SESSION_ID, sessionId).commit())
+                .isTrue();
+    }
+
+    private long readSessionIdFromDisk() {
+        final SharedPreferences sharedPref = getSharedPreferences();
+        final long sessionId = sharedPref.getLong(KEY_SESSION_ID, -1);
+        assertThat(sessionId).isNotEqualTo(-1);
+        return sessionId;
+    }
+
+    private void writeBlobHandleToDisk(BlobHandle handle) {
+        final SharedPreferences.Editor sharedPrefEditor = getSharedPreferences().edit();
+        sharedPrefEditor.putString(KEY_DIGEST, Base64.getEncoder().encodeToString(
+                handle.getSha256Digest()));
+        sharedPrefEditor.putString(KEY_LABEL, handle.getLabel().toString());
+        sharedPrefEditor.putLong(KEY_EXPIRY, handle.getExpiryTimeMillis());
+        sharedPrefEditor.putString(KEY_TAG, handle.getTag());
+        assertThat(sharedPrefEditor.commit()).isTrue();
+    }
+
+    private BlobHandle readBlobHandleFromDisk() {
+        final SharedPreferences sharedPref = getSharedPreferences();
+        final byte[] digest = Base64.getDecoder().decode(sharedPref.getString(KEY_DIGEST, null));
+        final CharSequence label = sharedPref.getString(KEY_LABEL, null);
+        final long expiryMillis = sharedPref.getLong(KEY_EXPIRY, -1);
+        final String tag = sharedPref.getString(KEY_TAG, null);
+        return BlobHandle.createWithSha256(digest, label, expiryMillis, tag);
+    }
+
+    private SharedPreferences getSharedPreferences() {
+        return mContext.getSharedPreferences(mContext.getPackageName(),
+                Context.MODE_PRIVATE);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
index 565573b..f2c3445 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -34,6 +34,7 @@
     <uses-permission android:name="android.permission.CAMERA" />
     <!-- Needed to read the serial number during Device ID attestation tests -->
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
     <!-- Add a network security config that trusts user added CAs for tests -->
     <application android:networkSecurityConfig="@xml/network_security_config"
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationHiddenParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationHiddenParentTest.java
new file mode 100644
index 0000000..aba1e59
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationHiddenParentTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.pm.PackageManager;
+
+public class ApplicationHiddenParentTest extends BaseDeviceAdminTest {
+
+    private DevicePolicyManager mParentDevicePolicyManager;
+    private PackageManager mPackageManager;
+
+    private static final String SYSTEM_PACKAGE_TO_HIDE = "com.google.android.youtube";
+    private static final String NON_SYSTEM_PACKAGE_TO_HIDE = "com.android.cts.permissionapp";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mParentDevicePolicyManager =
+                mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
+        mPackageManager = mContext.getPackageManager();
+        assertThat(mParentDevicePolicyManager).isNotNull();
+
+        assertThat(mDevicePolicyManager.isProfileOwnerApp(ADMIN_RECEIVER_COMPONENT.getPackageName())).isTrue();
+        assertThat(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).isTrue();
+    }
+
+    public void testSetApplicationHidden_systemPackage()
+            throws PackageManager.NameNotFoundException {
+        assertThat(mPackageManager.getPackageInfo(SYSTEM_PACKAGE_TO_HIDE, 0)).isNotNull();
+
+        assertThat(mParentDevicePolicyManager.setApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                SYSTEM_PACKAGE_TO_HIDE, true)).isTrue();
+        assertThat(mParentDevicePolicyManager.isApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                SYSTEM_PACKAGE_TO_HIDE)).isTrue();
+        assertThat(mPackageManager.getPackageInfo(SYSTEM_PACKAGE_TO_HIDE,
+                PackageManager.MATCH_UNINSTALLED_PACKAGES)).isNotNull();
+
+        assertThat(mParentDevicePolicyManager.setApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                SYSTEM_PACKAGE_TO_HIDE, false)).isTrue();
+        assertThat(mParentDevicePolicyManager.isApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                SYSTEM_PACKAGE_TO_HIDE)).isFalse();
+        assertThat(mPackageManager.getPackageInfo(SYSTEM_PACKAGE_TO_HIDE, 0)).isNotNull();
+    }
+
+    public void testSetApplicationHidden_nonSystemPackage() {
+        assertThrows(IllegalArgumentException.class, () -> {
+            mParentDevicePolicyManager.setApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                    NON_SYSTEM_PACKAGE_TO_HIDE, true);
+            mParentDevicePolicyManager.isApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                    NON_SYSTEM_PACKAGE_TO_HIDE);
+        });
+        assertThrows(IllegalArgumentException.class, () -> {
+            mParentDevicePolicyManager.setApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                    NON_SYSTEM_PACKAGE_TO_HIDE, false);
+            mParentDevicePolicyManager.isApplicationHidden(ADMIN_RECEIVER_COMPONENT,
+                    NON_SYSTEM_PACKAGE_TO_HIDE);
+        });
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
index 58a14e6..3c39f37 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
@@ -66,16 +66,16 @@
         mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
     }
 
-    public void startLockTask() throws Exception {
-        Log.d(TAG, "startLockTask on host-driven test (no cleanup)");
+    public void testStartLockTask_noAsserts() throws Exception {
+        Log.d(TAG, "testStartLockTask_noAsserts on host-driven test (no cleanup)");
         setLockTaskPackages(mContext.getPackageName());
         setDefaultHomeIntentReceiver();
         launchLockTaskActivity();
         mUiDevice.waitForIdle();
     }
 
-    public void cleanupLockTask() {
-        Log.d(TAG, "cleanupLockTask on host-driven test");
+    public void testCleanupLockTask_noAsserts() {
+        Log.d(TAG, "testCleanupLockTask_noAsserts on host-driven test");
         mDevicePolicyManager.clearPackagePersistentPreferredActivities(
                 ADMIN_RECEIVER_COMPONENT,
                 mContext.getPackageName());
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java
similarity index 93%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
rename to hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java
index b69a60c..1fd8eff 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.cts.deviceowner;
+package com.android.cts.deviceandprofileowner.systemupdate;
 
 import static android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID;
 
@@ -27,6 +27,7 @@
 import android.os.SystemProperties;
 
 import com.android.compatibility.common.util.SystemUtil;
+import com.android.cts.deviceandprofileowner.BaseDeviceAdminTest;
 
 import java.io.File;
 import java.util.concurrent.CountDownLatch;
@@ -35,7 +36,7 @@
 /**
  * Test {@link android.app.admin.DevicePolicyManager#installSystemUpdate}
  */
-public class InstallUpdateTest extends BaseDeviceOwnerTest {
+public class InstallUpdateTest extends BaseDeviceAdminTest {
     private static final int BATTERY_STATE_CHANGE_TIMEOUT_MS = 5000;
     private static final int BATTERY_STATE_CHANGE_SLEEP_PER_CHECK_MS = 50;
     private static final int TEST_BATTERY_THRESHOLD = 10;
@@ -150,7 +151,7 @@
             throws InterruptedException {
         CountDownLatch latch = new CountDownLatch(1);
         Uri uri = Uri.fromFile(new File(TEST_SYSTEM_UPDATES_DIR, fileName));
-        mDevicePolicyManager.installSystemUpdate(getWho(), uri,
+        mDevicePolicyManager.installSystemUpdate(ADMIN_RECEIVER_COMPONENT, uri,
                 Runnable::run, new InstallSystemUpdateCallback() {
                     @Override
                     public void onInstallUpdateError(int errorCode, String errorMessage) {
@@ -163,7 +164,7 @@
     }
 
     private void setNonChargingBatteryThreshold(int threshold) {
-        SystemUtil.runShellCommand(
+        runShellCommand(
                 "settings put global device_policy_constants battery_threshold_not_charging="
                         + threshold);
     }
@@ -173,7 +174,7 @@
     }
 
     private void setChargingBatteryThreshold(int threshold) {
-        SystemUtil.runShellCommand(
+        runShellCommand(
                 "settings put global device_policy_constants battery_threshold_charging="
                         + threshold);
     }
@@ -184,8 +185,8 @@
 
     /** Should be paired with {@link #resetBatteryState()} in a {@code finally} block. */
     private void setBatteryStateAndWait(boolean plugged, int level) throws Exception {
-        SystemUtil.runShellCommand(plugged ? "cmd battery set ac 1" : "cmd battery unplug");
-        SystemUtil.runShellCommand("cmd battery set -f level " + level);
+        runShellCommand(plugged ? "cmd battery set ac 1" : "cmd battery unplug");
+        runShellCommand("cmd battery set -f level " + level);
         long startTime = SystemClock.elapsedRealtime();
         while (!isBatteryState(plugged, level)
                 && SystemClock.elapsedRealtime() <= startTime + BATTERY_STATE_CHANGE_TIMEOUT_MS) {
@@ -211,11 +212,11 @@
     }
 
     private void resetBatteryState() {
-        SystemUtil.runShellCommand("dumpsys battery reset");
+        runShellCommand("dumpsys battery reset");
     }
 
     private void resetDevicePolicyConstants() {
-        SystemUtil.runShellCommand("settings delete global device_policy_constants");
+        runShellCommand("settings delete global device_policy_constants");
     }
 
     private boolean isDeviceAB() {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SystemUpdatePolicyTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/SystemUpdatePolicyTest.java
similarity index 94%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SystemUpdatePolicyTest.java
rename to hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/SystemUpdatePolicyTest.java
index e9d4126..44de098 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SystemUpdatePolicyTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/SystemUpdatePolicyTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.deviceowner;
+package com.android.cts.deviceandprofileowner.systemupdate;
 
 import static android.provider.Settings.Global.AIRPLANE_MODE_ON;
 
@@ -33,9 +33,8 @@
 import android.provider.Settings.Global;
 import android.util.Log;
 import android.util.Pair;
-import android.provider.Settings;
-import android.provider.Settings.Global;
 
+import com.android.cts.deviceandprofileowner.BaseDeviceAdminTest;
 import com.google.common.collect.ImmutableList;
 import java.time.LocalDate;
 import java.time.MonthDay;
@@ -50,7 +49,7 @@
  * Test {@link SystemUpdatePolicy}, {@link DevicePolicyManager#setSystemUpdatePolicy} and
  * {@link DevicePolicyManager#getSystemUpdatePolicy}
  */
-public class SystemUpdatePolicyTest extends BaseDeviceOwnerTest {
+public class SystemUpdatePolicyTest extends BaseDeviceAdminTest {
 
     private static final String TAG = "SystemUpdatePolicyTest";
 
@@ -86,7 +85,7 @@
         clearFreezeRecord();
         mSavedAutoTimeConfig = Settings.Global.getInt(mContext.getContentResolver(),
                 Global.AUTO_TIME, 0);
-        executeShellCommand("settings put global auto_time 0");
+        runShellCommand("settings put global auto_time 0");
         mSavedSystemDate = LocalDate.now();
         mRestoreDate = false;
         mSavedAirplaneMode = getAirplaneMode();
@@ -99,12 +98,12 @@
 
     @Override
     protected void tearDown() throws Exception {
-        mDevicePolicyManager.setSystemUpdatePolicy(getWho(), null);
+        mDevicePolicyManager.setSystemUpdatePolicy(ADMIN_RECEIVER_COMPONENT, null);
         clearFreezeRecord();
         if (mRestoreDate) {
             setSystemDate(mSavedSystemDate);
         }
-        executeShellCommand("settings put global auto_time",
+        runShellCommand("settings put global auto_time",
                 Integer.toString(mSavedAutoTimeConfig));
         // This needs to happen last since setSystemDate() relies on the receiver for
         // synchronization.
@@ -213,7 +212,7 @@
         setSystemDate(LocalDate.of(2018, 2, 28));
         setPolicyWithFreezePeriod("01-01", "03-01", "06-01", "06-30");
         // Clear policy
-        mDevicePolicyManager.setSystemUpdatePolicy(getWho(), null);
+        mDevicePolicyManager.setSystemUpdatePolicy(ADMIN_RECEIVER_COMPONENT, null);
         // Set to a conflict period (too close with previous period [2-28, 2-28]) should fail,
         // despite the previous policy was cleared from the system just now.
         try {
@@ -363,7 +362,7 @@
     }
 
     private void testPolicy(SystemUpdatePolicy policy) {
-        mDevicePolicyManager.setSystemUpdatePolicy(getWho(), policy);
+        mDevicePolicyManager.setSystemUpdatePolicy(ADMIN_RECEIVER_COMPONENT, policy);
         waitForPolicyChangedBroadcast();
         SystemUpdatePolicy newPolicy = mDevicePolicyManager.getSystemUpdatePolicy();
         if (policy == null) {
@@ -382,7 +381,7 @@
     private void setPolicyWithFreezePeriod(String...dates) {
         SystemUpdatePolicy policy = SystemUpdatePolicy.createPostponeInstallPolicy();
         setFreezePeriods(policy, dates);
-        mDevicePolicyManager.setSystemUpdatePolicy(getWho(), policy);
+        mDevicePolicyManager.setSystemUpdatePolicy(ADMIN_RECEIVER_COMPONENT, policy);
 
         List<FreezePeriod> loadedFreezePeriods = mDevicePolicyManager
                 .getSystemUpdatePolicy().getFreezePeriods();
@@ -438,7 +437,7 @@
     }
 
     private void clearFreezeRecord() throws Exception {
-        executeShellCommand("dpm", "clear-freeze-period-record");
+        runShellCommand("dpm", "clear-freeze-period-record");
     }
 
     private void setSystemDate(LocalDate date) throws Exception {
@@ -447,11 +446,16 @@
         c.set(Calendar.YEAR, date.getYear());
         c.set(Calendar.MONTH, date.getMonthValue() - 1);
         c.set(Calendar.DAY_OF_MONTH, date.getDayOfMonth());
-        mDevicePolicyManager.setTime(getWho(), c.getTimeInMillis());
+        mDevicePolicyManager.setTime(ADMIN_RECEIVER_COMPONENT, c.getTimeInMillis());
         waitForTimeChangedBroadcast();
     }
 
     private void waitForPolicyChangedBroadcast() {
+        if (!isDeviceOwner()) {
+            // ACTION_SYSTEM_UPDATE_POLICY_CHANGED is always sent to system user, skip
+            // waiting for it if we are inside a managed profile.
+            return;
+        }
         try {
             assertTrue("Timeout while waiting for broadcast.",
                     mPolicyChangedSemaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
@@ -469,8 +473,8 @@
         }
     }
 
-    private int getAirplaneMode() throws Settings.SettingNotFoundException {
-        int airplaneMode = 0xFF;
+    private int getAirplaneMode() {
+        int airplaneMode;
         try {
             airplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON);
@@ -478,9 +482,8 @@
             airplaneMode = 0xFF;
             // if the mode is not supported, return a non zero value.
             Log.i(TAG, "Airplane mode is not found in Settings. Skipping AirplaneMode update");
-        } finally {
-            return airplaneMode;
         }
+        return airplaneMode;
     }
 
     private boolean setAirplaneModeAndWaitBroadcast (int state) throws Exception {
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
index bb87c64..c494db0 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
@@ -90,6 +90,8 @@
             .add("addUserRestriction")
             .add("clearUserRestriction")
             .add("getUserRestrictions")
+            .add("setApplicationHidden")
+            .add("isApplicationHidden")
             .build();
 
     private static final String LOG_TAG = "ParentProfileTest";
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 08788e9..7d9dcd5 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -41,13 +41,18 @@
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.TarUtil;
 
+import com.google.common.io.ByteStreams;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -129,6 +134,14 @@
      */
     protected static final int USER_ALL = -1;
 
+    private static final String TEST_UPDATE_LOCATION = "/data/local/tmp/cts/deviceowner";
+
+    /**
+     * Copied from {@link android.app.admin.DevicePolicyManager
+     * .InstallSystemUpdateCallback#UPDATE_ERROR_UPDATE_FILE_INVALID}
+     */
+    protected static final int UPDATE_ERROR_UPDATE_FILE_INVALID = 3;
+
     protected CompatibilityBuildHelper mBuildHelper;
     private String mPackageVerifier;
     private HashSet<String> mAvailableFeatures;
@@ -202,6 +215,7 @@
                 mFixedUsers.add(getDevice().getCurrentUser());
             }
         }
+        getDevice().executeShellCommand(" mkdir " + TEST_UPDATE_LOCATION);
 
         removeOwners();
         switchUser(USER_SYSTEM);
@@ -226,6 +240,7 @@
         }
         removeTestUsers();
         removeTestPackages();
+        getDevice().executeShellCommand(" rm -r " + TEST_UPDATE_LOCATION);
     }
 
     protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException,
@@ -952,4 +967,22 @@
         }
         throw new Exception("Default launcher not found");
     }
+
+    boolean isDeviceAb() throws DeviceNotAvailableException {
+        final String result = getDevice().executeShellCommand("getprop ro.build.ab_update").trim();
+        return "true".equalsIgnoreCase(result);
+    }
+
+    void pushUpdateFileToDevice(String fileName)
+            throws IOException, DeviceNotAvailableException {
+        File file = File.createTempFile(
+                fileName.split("\\.")[0], "." + fileName.split("\\.")[1]);
+        try (OutputStream outputStream = new FileOutputStream(file)) {
+            InputStream inputStream = getClass().getResourceAsStream("/" + fileName);
+            ByteStreams.copy(inputStream, outputStream);
+        }
+
+        getDevice().pushFile(file, TEST_UPDATE_LOCATION + "/" + fileName);
+        file.delete();
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 7f69e58..2d3fd0d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -1196,7 +1196,8 @@
 
         try {
             // Just start kiosk mode
-            executeDeviceTestMethod(".LockTaskHostDrivenTest", "startLockTask");
+            executeDeviceTestMethod(
+                    ".LockTaskHostDrivenTest", "testStartLockTask_noAsserts");
 
             // Reboot while in kiosk mode and then unlock the device
             rebootAndWaitUntilReady();
@@ -1205,7 +1206,7 @@
             executeDeviceTestMethod(".LockTaskHostDrivenTest",
                     "testLockTaskIsActiveAndCantBeInterrupted");
         } finally {
-            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "testCleanupLockTask_noAsserts");
         }
     }
 
@@ -1218,7 +1219,8 @@
 
         try {
             // Just start kiosk mode
-            executeDeviceTestMethod(".LockTaskHostDrivenTest", "startLockTask");
+            executeDeviceTestMethod(
+                    ".LockTaskHostDrivenTest", "testStartLockTask_noAsserts");
 
             // Reboot while in kiosk mode and then unlock the device
             rebootAndWaitUntilReady();
@@ -1230,7 +1232,7 @@
             executeDeviceTestMethod(".LockTaskHostDrivenTest",
                     "testLockTaskIsActiveAndCantBeInterrupted");
         } finally {
-            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "testCleanupLockTask_noAsserts");
         }
     }
 
@@ -1243,7 +1245,7 @@
             executeDeviceTestMethod(".LockTaskHostDrivenTest",
                     "testLockTaskCanLaunchDefaultDialer");
         } finally {
-            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "testCleanupLockTask_noAsserts");
         }
     }
 
@@ -1256,7 +1258,7 @@
             executeDeviceTestMethod(".LockTaskHostDrivenTest",
                     "testLockTaskCanLaunchEmergencyDialer");
         } finally {
-            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "testCleanupLockTask_noAsserts");
         }
     }
 
@@ -1269,7 +1271,7 @@
             executeDeviceTestMethod(".LockTaskHostDrivenTest",
                     "testLockTaskIsExitedIfNotWhitelisted");
         } finally {
-            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "testCleanupLockTask_noAsserts");
         }
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 186970c..cdf5bd9 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -32,8 +32,6 @@
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.device.DeviceNotAvailableException;
 
-import com.google.common.io.ByteStreams;
-
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -84,17 +82,10 @@
     private static final int SECURITY_EVENTS_BATCH_SIZE = 100;
 
     private static final String ARG_NETWORK_LOGGING_BATCH_COUNT = "batchCount";
-    private static final String TEST_UPDATE_LOCATION = "/data/local/tmp/cts/deviceowner";
 
     private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
             "CtsHasLauncherActivityApp.apk";
 
-    /**
-     * Copied from {@link android.app.admin.DevicePolicyManager
-     * .InstallSystemUpdateCallback#UPDATE_ERROR_UPDATE_FILE_INVALID}
-     */
-    private static final int UPDATE_ERROR_UPDATE_FILE_INVALID = 3;
-
     private static final int TYPE_NONE = 0;
 
     /**
@@ -135,7 +126,6 @@
                 fail("Failed to set device owner");
             }
 
-            getDevice().executeShellCommand(" mkdir " + TEST_UPDATE_LOCATION);
             // Enable the notification listener
             getDevice().executeShellCommand("cmd notification allow_listener com.android.cts.deviceowner/com.android.cts.deviceowner.NotificationListener");
         }
@@ -151,7 +141,6 @@
             getDevice().uninstallPackage(DEVICE_OWNER_PKG);
             switchUser(USER_SYSTEM);
             removeTestUsers();
-            getDevice().executeShellCommand(" rm -r " + TEST_UPDATE_LOCATION);
         }
 
         super.tearDown();
@@ -622,16 +611,6 @@
         executeDeviceTestMethod(".AffiliationTest", "testSetAffiliationId_containsEmptyString");
     }
 
-    @LargeTest
-    @Test
-    @Ignore("b/145932189")
-    public void testSystemUpdatePolicy() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-        executeDeviceOwnerTest("SystemUpdatePolicyTest");
-    }
-
     @Test
     @Ignore("b/145932189")
     public void testSetSystemUpdatePolicyLogged() throws Exception {
@@ -1003,55 +982,6 @@
     }
 
     @Test
-    public void testInstallUpdate() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-
-        pushUpdateFileToDevice("notZip.zi");
-        pushUpdateFileToDevice("empty.zip");
-        pushUpdateFileToDevice("wrongPayload.zip");
-        pushUpdateFileToDevice("wrongHash.zip");
-        pushUpdateFileToDevice("wrongSize.zip");
-        executeDeviceOwnerTest("InstallUpdateTest");
-    }
-
-    @Test
-    public void testInstallUpdateLogged() throws Exception {
-        if (!mHasFeature || !isDeviceAb() || !isStatsdEnabled(getDevice())) {
-            return;
-        }
-        pushUpdateFileToDevice("wrongHash.zip");
-        assertMetricsLogged(getDevice(), () -> {
-            executeDeviceTestMethod(".InstallUpdateTest", "testInstallUpdate_failWrongHash");
-        }, new DevicePolicyEventWrapper.Builder(EventId.INSTALL_SYSTEM_UPDATE_VALUE)
-                    .setAdminPackageName(DEVICE_OWNER_PKG)
-                    .setBoolean(/* isDeviceAb */ true)
-                    .build(),
-            new DevicePolicyEventWrapper.Builder(EventId.INSTALL_SYSTEM_UPDATE_ERROR_VALUE)
-                    .setInt(UPDATE_ERROR_UPDATE_FILE_INVALID)
-                    .build());
-    }
-
-    private boolean isDeviceAb() throws DeviceNotAvailableException {
-        final String result = getDevice().executeShellCommand("getprop ro.build.ab_update").trim();
-        return "true".equalsIgnoreCase(result);
-    }
-
-    private void pushUpdateFileToDevice(String fileName)
-            throws IOException, DeviceNotAvailableException {
-        File file = File.createTempFile(
-                fileName.split("\\.")[0], "." + fileName.split("\\.")[1]);
-        try (OutputStream outputStream = new FileOutputStream(file)) {
-            InputStream inputStream = getClass().getResourceAsStream("/" + fileName);
-            ByteStreams.copy(inputStream, outputStream);
-        }
-
-        getDevice().pushFile(file, TEST_UPDATE_LOCATION + "/" + fileName);
-        file.delete();
-    }
-
-    @Test
     public void testSetKeyguardDisabledLogged() throws Exception {
         if (!mHasFeature || !isStatsdEnabled(getDevice())) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index e89ef59..649925c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -23,12 +23,19 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.FlakyTest;
+import android.platform.test.annotations.LargeTest;
 import android.stats.devicepolicy.EventId;
 
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -243,6 +250,48 @@
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".CommonCriteriaModeTest", mUserId);
     }
 
+    @LargeTest
+    @Test
+    @Ignore("b/145932189")
+    public void testSystemUpdatePolicy() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".systemupdate.SystemUpdatePolicyTest", mUserId);
+    }
+
+    @Test
+    public void testInstallUpdate() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        pushUpdateFileToDevice("notZip.zi");
+        pushUpdateFileToDevice("empty.zip");
+        pushUpdateFileToDevice("wrongPayload.zip");
+        pushUpdateFileToDevice("wrongHash.zip");
+        pushUpdateFileToDevice("wrongSize.zip");
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".systemupdate.InstallUpdateTest", mUserId);
+    }
+
+    @Test
+    public void testInstallUpdateLogged() throws Exception {
+        if (!mHasFeature || !isDeviceAb() || !isStatsdEnabled(getDevice())) {
+            return;
+        }
+        pushUpdateFileToDevice("wrongHash.zip");
+        assertMetricsLogged(getDevice(), () -> {
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".systemupdate.InstallUpdateTest",
+                    "testInstallUpdate_failWrongHash", mUserId);
+        }, new DevicePolicyEventWrapper.Builder(EventId.INSTALL_SYSTEM_UPDATE_VALUE)
+                    .setAdminPackageName(DEVICE_ADMIN_PKG)
+                    .setBoolean(/* isDeviceAb */ true)
+                    .build(),
+            new DevicePolicyEventWrapper.Builder(EventId.INSTALL_SYSTEM_UPDATE_ERROR_VALUE)
+                    .setInt(UPDATE_ERROR_UPDATE_FILE_INVALID)
+                    .build());
+    }
+
     private int createSecondaryUserAsProfileOwner() throws Exception {
         final int userId = createUser();
         installAppAsUser(INTENT_RECEIVER_APK, userId);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
index 1cdd8f4..ef8b14e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
@@ -16,16 +16,21 @@
 
 package com.android.cts.devicepolicy;
 
+import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.assertMetricsLogged;
+import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.isStatsdEnabled;
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.platform.test.annotations.FlakyTest;
+import android.platform.test.annotations.LargeTest;
 
+import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -266,8 +271,31 @@
             return;
         }
 
-        runDeviceTestsAsUser(
-                DEVICE_ADMIN_PKG, ".FactoryResetProtectionPolicyTest", mUserId);
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".FactoryResetProtectionPolicyTest", mUserId);
+    }
+
+    @LargeTest
+    @Test
+    @Ignore("b/145932189")
+    public void testSystemUpdatePolicy() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".systemupdate.SystemUpdatePolicyTest", mUserId);
+    }
+
+    @Test
+    public void testInstallUpdate() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        pushUpdateFileToDevice("notZip.zi");
+        pushUpdateFileToDevice("empty.zip");
+        pushUpdateFileToDevice("wrongPayload.zip");
+        pushUpdateFileToDevice("wrongHash.zip");
+        pushUpdateFileToDevice("wrongSize.zip");
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".systemupdate.InstallUpdateTest", mUserId);
     }
 
     @Test
@@ -302,6 +330,15 @@
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".AdminConfiguredNetworksTest", mUserId);
     }
 
+    @Test
+    public void testApplicationHidden() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".ApplicationHiddenParentTest", mUserId);
+    }
+
     private void removeOrgOwnedProfile() throws DeviceNotAvailableException {
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, RELINQUISH_DEVICE_TEST_CLASS, mUserId);
     }
diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
index 1356600..ea1f803 100644
--- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
@@ -107,6 +107,8 @@
         int veryJankyDelta = countFramesAbove(statsAfter, 60) - countFramesAbove(statsBefore, 60);
         // The 1st frame could be >40ms, but nothing after that should be
         assertTrue(veryJankyDelta <= 2);
+        int noGPUJank = countGPUFramesAbove(statsAfter, 60) - countGPUFramesAbove(statsBefore, 60);
+        assertTrue(noGPUJank == 0);
     }
 
     public void testDaveyDrawFrame() throws Exception {
@@ -181,6 +183,9 @@
         assertTrue(summary.getSlowBitmapUploadCount() <= summary.getJankyFrames());
         assertTrue(summary.getSlowDrawCount() <= summary.getJankyFrames());
         assertTrue(proto.getHistogramCount() > 0);
+        assertTrue(proto.getGpuHistogramCount() > 0);
+        assertTrue(proto.getPipeline() == GraphicsStatsProto.PipelineType.GL
+            || proto.getPipeline() == GraphicsStatsProto.PipelineType.VULKAN);
 
         int histogramTotal = countTotalFrames(proto);
         assertEquals(summary.getTotalFrames(), histogramTotal);
@@ -196,6 +201,16 @@
         return totalFrames;
     }
 
+    private int countGPUFramesAbove(GraphicsStatsProto proto, int thresholdMs) {
+        int totalFrames = 0;
+        for (GraphicsStatsHistogramBucketProto bucket : proto.getGpuHistogramList()) {
+            if (bucket.getRenderMillis() >= thresholdMs) {
+                totalFrames += bucket.getFrameCount();
+            }
+        }
+        return totalFrames;
+    }
+
     private int countTotalFrames(GraphicsStatsProto proto) {
         return countFramesAbove(proto, 0);
     }
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
index 137100b..ef0a5cb 100755
--- a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
@@ -57,6 +57,8 @@
             outMsg->body.key.source = msg.body.key.source;
             // int32_t displayId
             outMsg->body.key.displayId = msg.body.key.displayId;
+            // std::array<uint8_t, 32> hmac
+            outMsg->body.key.hmac = msg.body.key.hmac;
             // int32_t action
             outMsg->body.key.action = msg.body.key.action;
             // int32_t flags
@@ -84,6 +86,8 @@
             outMsg->body.motion.source = msg.body.motion.source;
             // int32_t displayId
             outMsg->body.motion.displayId = msg.body.motion.displayId;
+            // std::array<uint8_t, 32> hmac
+            outMsg->body.motion.hmac = msg.body.motion.hmac;
             // int32_t action
             outMsg->body.motion.action = msg.body.motion.action;
             // int32_t actionButton
@@ -100,6 +104,10 @@
             outMsg->body.motion.edgeFlags = msg.body.motion.edgeFlags;
             // nsecs_t downTime
             outMsg->body.motion.downTime = msg.body.motion.downTime;
+            // float xScale
+            outMsg->body.motion.xScale = msg.body.motion.xScale;
+            // float yScale
+            outMsg->body.motion.yScale = msg.body.motion.yScale;
             // float xOffset
             outMsg->body.motion.xOffset = msg.body.motion.xOffset;
             // float yOffset
diff --git a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
index 25231b9b..9f3b4df 100644
--- a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
+++ b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
@@ -99,6 +99,20 @@
                 getDevice().getProperty("sys.init.userspace_reboot.last_finished")).isNotEmpty();
     }
 
+    @Test
+    public void testBootReasonProperty_shutdown_aborted() throws Exception {
+        getDevice().reboot("userspace_failed,shutdown_aborted");
+        assertThat(getDevice().getProperty("sys.boot.reason")).isEqualTo(
+                "reboot,userspace_failed,shutdown_aborted");
+    }
+
+    @Test
+    public void testBootReasonProperty_mount_userdata_failed() throws Exception {
+        getDevice().reboot("mount_userdata_failed");
+        assertThat(getDevice().getProperty("sys.boot.reason")).isEqualTo(
+                "reboot,mount_userdata_failed");
+    }
+
     // TODO(b/135984674): add test case that forces unmount of f2fs userdata.
 
     private boolean isFsCheckpointingSupported() throws Exception {
diff --git a/tests/BlobStore/Android.bp b/tests/BlobStore/Android.bp
index 06dd877..c168eb6 100644
--- a/tests/BlobStore/Android.bp
+++ b/tests/BlobStore/Android.bp
@@ -21,6 +21,7 @@
         "compatibility-device-util-axt",
         "truth-prebuilt",
         "testng",
+        "BlobStoreTestUtils",
     ],
     srcs: [
         "src/**/*.java",
diff --git a/tests/BlobStore/TEST_MAPPING b/tests/BlobStore/TEST_MAPPING
new file mode 100644
index 0000000..ee1df4c
--- /dev/null
+++ b/tests/BlobStore/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsBlobStoreTestCases"
+    }
+  ]
+}
diff --git a/tests/BlobStore/lib/Android.bp b/tests/BlobStore/lib/Android.bp
new file mode 100644
index 0000000..edd2b43
--- /dev/null
+++ b/tests/BlobStore/lib/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+java_library {
+  name: "BlobStoreTestUtils",
+  srcs: ["src/**/*.java"],
+  static_libs: ["truth-prebuilt"],
+  platform_apis: true
+}
\ No newline at end of file
diff --git a/tests/BlobStore/lib/src/com/android/cts/blob/DummyBlobData.java b/tests/BlobStore/lib/src/com/android/cts/blob/DummyBlobData.java
new file mode 100644
index 0000000..d31e15c
--- /dev/null
+++ b/tests/BlobStore/lib/src/com/android/cts/blob/DummyBlobData.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright 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.
+ */
+package com.android.cts.blob;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.blob.BlobHandle;
+import android.app.blob.BlobStoreManager;
+import android.content.Context;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.file.Files;
+import java.security.MessageDigest;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+public class DummyBlobData {
+    private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
+    private static final int BUFFER_SIZE_BYTES = 16 * 1024;
+
+    private final Context mContext;
+    private final Random mRandom;
+    private final File mFile;
+    private final long mFileSize;
+    private final String mLabel;
+
+    byte[] mFileDigest;
+    long mExpiryTimeMs;
+
+    public DummyBlobData(Context context) {
+        this(context, new Random(0), "blob_" + System.nanoTime());
+    }
+
+    public DummyBlobData(Context context, Random random, String fileName) {
+        this(context, DEFAULT_SIZE_BYTES, random, fileName, "Test label");
+    }
+
+    public DummyBlobData(Context context, Random random, String fileName, String label) {
+        this(context, DEFAULT_SIZE_BYTES, random, fileName, label);
+    }
+
+    public DummyBlobData(Context context, long fileSize, Random random, String fileName,
+            String label) {
+        mContext = context;
+        mRandom = random;
+        mFile = new File(mContext.getFilesDir(), fileName);
+        mFileSize = fileSize;
+        mLabel = label;
+    }
+
+    public void prepare() throws Exception {
+        try (RandomAccessFile file = new RandomAccessFile(mFile, "rw")) {
+            writeRandomData(file, mFileSize);
+        }
+        mFileDigest = FileUtils.digest(mFile, "SHA-256");
+        mExpiryTimeMs = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1);
+    }
+
+    public BlobHandle getBlobHandle() throws Exception {
+        return BlobHandle.createWithSha256(createSha256Digest(mFile), mLabel,
+                mExpiryTimeMs, "test_tag");
+    }
+
+    public long getFileSize() throws Exception {
+        return mFileSize;
+    }
+
+    public void delete() {
+        mFile.delete();
+    }
+
+    public void writeToSession(BlobStoreManager.Session session) throws Exception {
+        writeToSession(session, 0, mFileSize);
+    }
+
+    public void writeToSession(BlobStoreManager.Session session,
+            long offsetBytes, long lengthBytes) throws Exception {
+        try (FileInputStream in = new FileInputStream(mFile)) {
+            in.getChannel().position(offsetBytes);
+            try (FileOutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
+                    session.openWrite(offsetBytes, lengthBytes))) {
+                copy(in, out, lengthBytes);
+            }
+        }
+    }
+
+    public void writeToFd(FileDescriptor fd, long offsetBytes, long lengthBytes) throws Exception {
+        try (FileInputStream in = new FileInputStream(mFile)) {
+            in.getChannel().position(offsetBytes);
+            try (FileOutputStream out = new FileOutputStream(fd)) {
+                copy(in, out, lengthBytes);
+            }
+        }
+    }
+
+    private void copy(InputStream in, OutputStream out, long lengthBytes) throws Exception {
+        final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+        long bytesWrittern = 0;
+        while (bytesWrittern < lengthBytes) {
+            final int toWrite = (bytesWrittern + buffer.length <= lengthBytes)
+                    ? buffer.length : (int) (lengthBytes - bytesWrittern);
+            in.read(buffer, 0, toWrite);
+            out.write(buffer, 0, toWrite);
+            bytesWrittern += toWrite;
+        }
+    }
+
+    public void readFromSessionAndVerifyBytes(BlobStoreManager.Session session,
+            long offsetBytes, int lengthBytes) throws Exception {
+        final byte[] expectedBytes = new byte[lengthBytes];
+        try (FileInputStream in = new FileInputStream(mFile)) {
+            read(in, expectedBytes, offsetBytes, lengthBytes);
+        }
+
+        final byte[] actualBytes = new byte[lengthBytes];
+        try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
+                session.openWrite(0L, 0L))) {
+            read(in, actualBytes, offsetBytes, lengthBytes);
+        }
+
+        assertThat(actualBytes).isEqualTo(expectedBytes);
+
+    }
+
+    private void read(FileInputStream in, byte[] buffer,
+            long offsetBytes, int lengthBytes) throws Exception {
+        in.getChannel().position(offsetBytes);
+        in.read(buffer, 0, lengthBytes);
+    }
+
+    public void readFromSessionAndVerifyDigest(BlobStoreManager.Session session)
+            throws Exception {
+        readFromSessionAndVerifyDigest(session, 0, mFile.length());
+    }
+
+    public void readFromSessionAndVerifyDigest(BlobStoreManager.Session session,
+            long offsetBytes, long lengthBytes) throws Exception {
+        final byte[] actualDigest;
+        try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
+                session.openWrite(0L, 0L))) {
+            actualDigest = createSha256Digest(in, offsetBytes, lengthBytes);
+        }
+
+        assertThat(actualDigest).isEqualTo(mFileDigest);
+    }
+
+    public void verifyBlob(ParcelFileDescriptor pfd) throws Exception {
+        final byte[] actualDigest;
+        try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+            actualDigest = FileUtils.digest(in, "SHA-256");
+        }
+        assertThat(actualDigest).isEqualTo(mFileDigest);
+    }
+
+    private byte[] createSha256Digest(FileInputStream in, long offsetBytes, long lengthBytes)
+            throws Exception {
+        final MessageDigest digest = MessageDigest.getInstance("SHA-256");
+        in.getChannel().position(offsetBytes);
+        final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+        long bytesRead = 0;
+        while (bytesRead < lengthBytes) {
+            int toRead = (bytesRead + buffer.length <= lengthBytes)
+                    ? buffer.length : (int) (lengthBytes - bytesRead);
+            toRead = in.read(buffer, 0, toRead);
+            digest.update(buffer, 0, toRead);
+            bytesRead += toRead;
+        }
+        return digest.digest();
+    }
+
+    private byte[] createSha256Digest(File file) throws Exception {
+        final MessageDigest digest = MessageDigest.getInstance("SHA-256");
+        try (BufferedInputStream in = new BufferedInputStream(
+                Files.newInputStream(file.toPath()))) {
+            final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+            int bytesRead;
+            while ((bytesRead = in.read(buffer)) > 0) {
+                digest.update(buffer, 0, bytesRead);
+            }
+        }
+        return digest.digest();
+    }
+
+    private void writeRandomData(RandomAccessFile file, long fileSize)
+            throws Exception {
+        long bytesWritten = 0;
+        final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+        while (bytesWritten < fileSize) {
+            mRandom.nextBytes(buffer);
+            final int toWrite = (bytesWritten + buffer.length <= fileSize)
+                    ? buffer.length : (int) (fileSize - bytesWritten);
+            file.seek(bytesWritten);
+            file.write(buffer, 0, toWrite);
+            bytesWritten += toWrite;
+        }
+    }
+}
diff --git a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
index 52fc287..3979e6c 100644
--- a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
+++ b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
@@ -22,7 +22,6 @@
 import android.app.blob.BlobHandle;
 import android.app.blob.BlobStoreManager;
 import android.content.Context;
-import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 
 import com.android.cts.blob.R;
@@ -32,19 +31,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.nio.file.Files;
-import java.security.MessageDigest;
 import java.util.ArrayList;
-import java.util.Random;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
@@ -57,7 +45,6 @@
 
     private Context mContext;
     private BlobStoreManager mBlobStoreManager;
-    private Random mRandom;
 
     private final ArrayList<Long> mCreatedSessionIds = new ArrayList<>();
 
@@ -66,7 +53,6 @@
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mBlobStoreManager = (BlobStoreManager) mContext.getSystemService(
                 Context.BLOB_STORE_SERVICE);
-        mRandom = new Random(0);
         mCreatedSessionIds.clear();
     }
 
@@ -83,7 +69,7 @@
 
     @Test
     public void testGetCreateSession() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -96,7 +82,7 @@
 
     @Test
     public void testDeleteSession() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -114,13 +100,13 @@
 
     @Test
     public void testOpenReadWriteSession() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
             assertThat(sessionId).isGreaterThan(0L);
             try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
-                blobData.writeToSession(session, 0, blobData.mFileSize);
+                blobData.writeToSession(session, 0, blobData.getFileSize());
                 blobData.readFromSessionAndVerifyDigest(session);
                 blobData.readFromSessionAndVerifyBytes(session,
                         101 /* offset */, 1001 /* length */);
@@ -136,7 +122,7 @@
 
     @Test
     public void testAbandonSession() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -161,7 +147,7 @@
 
     @Test
     public void testCloseSession() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -197,7 +183,7 @@
 
     @Test
     public void testAllowPublicAccess() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -220,7 +206,7 @@
 
     @Test
     public void testAllowSameSignatureAccess() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -243,7 +229,7 @@
 
     @Test
     public void testAllowPackageAccess() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -269,7 +255,7 @@
 
     @Test
     public void testMixedAccessType() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -294,7 +280,7 @@
 
     @Test
     public void testSessionCommit() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -325,7 +311,7 @@
 
     @Test
     public void testOpenBlob() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -357,7 +343,7 @@
 
     @Test
     public void testAcquireReleaseLease() throws Exception {
-        final DummyBlobData blobData = new DummyBlobData();
+        final DummyBlobData blobData = new DummyBlobData(mContext);
         blobData.prepare();
         try {
             final long sessionId = createSession(blobData.getBlobHandle());
@@ -391,167 +377,4 @@
         mCreatedSessionIds.add(sessionId);
         return sessionId;
     }
-
-    class DummyBlobData {
-        private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
-        private static final int BUFFER_SIZE_BYTES = 16 * 1024;
-
-        final File mFile;
-        final long mFileSize;
-
-        byte[] mFileDigest;
-        long mExpiryTimeMs;
-
-        DummyBlobData() {
-            this(DEFAULT_SIZE_BYTES);
-        }
-
-        DummyBlobData(long fileSize) {
-            mFile = new File(mContext.getFilesDir(), "blob_" + System.nanoTime());
-            mFileSize = fileSize;
-        }
-
-        void prepare() throws Exception {
-            try (RandomAccessFile file = new RandomAccessFile(mFile, "rw")) {
-                writeRandomData(file, mFileSize);
-            }
-            mFileDigest = FileUtils.digest(mFile, "SHA-256");
-            mExpiryTimeMs = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1);
-        }
-
-        BlobHandle getBlobHandle() throws Exception {
-            return BlobHandle.createWithSha256(createSha256Digest(mFile), "Test blob",
-                    mExpiryTimeMs, "test_tag");
-        }
-
-        void delete() {
-            mFile.delete();
-        }
-
-        void writeToSession(BlobStoreManager.Session session) throws Exception {
-            writeToSession(session, 0, mFileSize);
-        }
-
-        void writeToSession(BlobStoreManager.Session session, long offsetBytes, long lengthBytes)
-                throws Exception {
-            try (FileInputStream in = new FileInputStream(mFile)) {
-                in.getChannel().position(offsetBytes);
-                try (FileOutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
-                        session.openWrite(offsetBytes, lengthBytes))) {
-                    copy(in, out, lengthBytes);
-                }
-            }
-        }
-
-        void writeToFd(FileDescriptor fd, long offsetBytes, long lengthBytes) throws Exception {
-            try (FileInputStream in = new FileInputStream(mFile)) {
-                in.getChannel().position(offsetBytes);
-                try (FileOutputStream out = new FileOutputStream(fd)) {
-                    copy(in, out, lengthBytes);
-                }
-            }
-        }
-
-        void copy(InputStream in, OutputStream out, long lengthBytes) throws Exception {
-            final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
-            long bytesWrittern = 0;
-            while (bytesWrittern < lengthBytes) {
-                final int toWrite = (bytesWrittern + buffer.length <= lengthBytes)
-                        ? buffer.length : (int) (lengthBytes - bytesWrittern);
-                in.read(buffer, 0, toWrite);
-                out.write(buffer, 0, toWrite);
-                bytesWrittern += toWrite;
-            }
-        }
-
-        void readFromSessionAndVerifyBytes(BlobStoreManager.Session session,
-                long offsetBytes, int lengthBytes) throws Exception {
-            final byte[] expectedBytes = new byte[lengthBytes];
-            try (FileInputStream in = new FileInputStream(mFile)) {
-                read(in, expectedBytes, offsetBytes, lengthBytes);
-            }
-
-            final byte[] actualBytes = new byte[lengthBytes];
-            try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
-                    session.openWrite(0L, 0L))) {
-                read(in, actualBytes, offsetBytes, lengthBytes);
-            }
-
-            assertThat(actualBytes).isEqualTo(expectedBytes);
-
-        }
-
-        private void read(FileInputStream in, byte[] buffer,
-                long offsetBytes, int lengthBytes) throws Exception {
-            in.getChannel().position(offsetBytes);
-            in.read(buffer, 0, lengthBytes);
-        }
-
-        void readFromSessionAndVerifyDigest(BlobStoreManager.Session session)
-                throws Exception {
-            readFromSessionAndVerifyDigest(session, 0, mFile.length());
-        }
-
-        void readFromSessionAndVerifyDigest(BlobStoreManager.Session session,
-                long offsetBytes, long lengthBytes) throws Exception {
-            final byte[] actualDigest;
-            try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
-                    session.openWrite(0L, 0L))) {
-                actualDigest = createSha256Digest(in, offsetBytes, lengthBytes);
-            }
-
-            assertThat(actualDigest).isEqualTo(mFileDigest);
-        }
-
-        void verifyBlob(ParcelFileDescriptor pfd) throws Exception {
-            final byte[] actualDigest;
-            try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
-                actualDigest = FileUtils.digest(in, "SHA-256");
-            }
-            assertThat(actualDigest).isEqualTo(mFileDigest);
-        }
-
-        private byte[] createSha256Digest(FileInputStream in, long offsetBytes, long lengthBytes)
-                throws Exception {
-            final MessageDigest digest = MessageDigest.getInstance("SHA-256");
-            in.getChannel().position(offsetBytes);
-            final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
-            long bytesRead = 0;
-            while (bytesRead < lengthBytes) {
-                int toRead = (bytesRead + buffer.length <= lengthBytes)
-                        ? buffer.length : (int) (lengthBytes - bytesRead);
-                toRead = in.read(buffer, 0, toRead);
-                digest.update(buffer, 0, toRead);
-                bytesRead += toRead;
-            }
-            return digest.digest();
-        }
-
-        private byte[] createSha256Digest(File file) throws Exception {
-            final MessageDigest digest = MessageDigest.getInstance("SHA-256");
-            try (BufferedInputStream in = new BufferedInputStream(
-                    Files.newInputStream(file.toPath()))) {
-                final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
-                int bytesRead;
-                while ((bytesRead = in.read(buffer)) > 0) {
-                    digest.update(buffer, 0, bytesRead);
-                }
-            }
-            return digest.digest();
-        }
-
-        private void writeRandomData(RandomAccessFile file, long fileSize)
-                throws Exception {
-            long bytesWritten = 0;
-            final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
-            while (bytesWritten < fileSize) {
-                mRandom.nextBytes(buffer);
-                final int toWrite = (bytesWritten + buffer.length <= fileSize)
-                        ? buffer.length : (int) (fileSize - bytesWritten);
-                file.seek(bytesWritten);
-                file.write(buffer, 0, toWrite);
-                bytesWritten += toWrite;
-            }
-        }
-    }
 }
diff --git a/tests/accessibilityservice/res/xml/stub_gesture_detect_a11y_service.xml b/tests/accessibilityservice/res/xml/stub_gesture_detect_a11y_service.xml
index ca3eab2..7e74518 100644
--- a/tests/accessibilityservice/res/xml/stub_gesture_detect_a11y_service.xml
+++ b/tests/accessibilityservice/res/xml/stub_gesture_detect_a11y_service.xml
@@ -20,7 +20,7 @@
         android:description="@string/stub_gesture_detector_a11y_service_description"
         android:accessibilityEventTypes="typeAllMask"
         android:accessibilityFeedbackType="feedbackGeneric"
-        android:accessibilityFlags="flagDefault|flagRequestTouchExplorationMode|flagReportViewIds"
+        android:accessibilityFlags="flagDefault|flagRequestTouchExplorationMode|flagReportViewIds|flagServiceHandlesDoubleTap"
         android:canRequestTouchExplorationMode="true"
         android:canRetrieveWindowContent="true"
         android:canPerformGestures="true" />
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 8918de3..3bdf81f4 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -15,11 +15,11 @@
 package android.accessibilityservice.cts;
 
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityOnSpecifiedDisplayAndWaitForItToBeOnscreen;
+import static android.accessibilityservice.cts.utils.DisplayUtils.VirtualDisplaySession;
 import static android.accessibilityservice.cts.utils.GestureUtils.click;
 import static android.accessibilityservice.cts.utils.GestureUtils.endTimeOf;
 import static android.accessibilityservice.cts.utils.GestureUtils.longClick;
 import static android.accessibilityservice.cts.utils.GestureUtils.startingAt;
-import static android.accessibilityservice.cts.utils.DisplayUtils.VirtualDisplaySession;
 import static android.app.UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES;
 
 import static org.junit.Assert.assertEquals;
@@ -149,6 +149,10 @@
         final int dy = mStrokeLenPxY;
 
         // Test recognizing various gestures.
+        testGesture(doubleTap(Display.DEFAULT_DISPLAY), AccessibilityService.GESTURE_DOUBLE_TAP);
+        testGesture(
+                doubleTapAndHold(Display.DEFAULT_DISPLAY),
+                AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD);
         testPath(p(-dx, +0), AccessibilityService.GESTURE_SWIPE_LEFT);
         testPath(p(+dx, +0), AccessibilityService.GESTURE_SWIPE_RIGHT);
         testPath(p(+0, -dy), AccessibilityService.GESTURE_SWIPE_UP);
@@ -191,6 +195,14 @@
 
             try {
                 // Test recognizing various gestures.
+                testGesture(
+                        doubleTap(displayId),
+                        AccessibilityService.GESTURE_DOUBLE_TAP,
+                        displayId);
+                testGesture(
+                        doubleTapAndHold(displayId),
+                        AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD,
+                        displayId);
                 testPath(p(-dx, +0), AccessibilityService.GESTURE_SWIPE_LEFT, displayId);
                 testPath(p(+dx, +0), AccessibilityService.GESTURE_SWIPE_RIGHT, displayId);
                 testPath(p(+0, -dy), AccessibilityService.GESTURE_SWIPE_UP, displayId);
@@ -265,6 +277,11 @@
                 .setDisplayId(displayId)
                 .build();
 
+        testGesture(gesture, gestureId, displayId);
+    }
+
+    /** Dispatch a gesture and make sure it is detected as the specified gesture id. */
+    private void testGesture(GestureDescription gesture, int gestureId, int displayId) {
         // Dispatch gesture motions to specified  display with GestureDescription..
         // Use AccessibilityService.dispatchGesture() instead of Instrumentation.sendPointerSync()
         // because accessibility services read gesture events upstream from the point where
@@ -288,6 +305,10 @@
         assertEquals(expectedGestureEvent.toString(), mService.getGestureInfo(0).toString());
     }
 
+    private void testGesture(GestureDescription gesture, int gestureId) {
+        testGesture(gesture, gestureId, Display.DEFAULT_DISPLAY);
+    }
+
     /** Create a path from startPoint, moving by delta1, then delta2. (delta2 may be null.) */
     Path linePath(Point startPoint, Point delta1, Point delta2) {
         Path path = new Path();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
index 553254f..9042d62 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
@@ -258,7 +258,9 @@
     /**
      * Test the case where we execute a "sloppy" double tap, meaning that the second tap isn't
      * exactly in the same location as the first but still within tolerances. It should behave the
-     * same as a standard double tap.
+     * same as a standard double tap. Note that this test does not request that double tap be
+     * dispatched to the accessibility service, meaning that it will be handled by the framework and
+     * the view will be clicked.
      */
     @Test
     @AppModeFull
@@ -280,7 +282,9 @@
 
     /**
      * Test the case where we want to click on the item that has accessibility focus by using
-     * AccessibilityNodeInfo.performAction.
+     * AccessibilityNodeInfo.performAction. Note that this test does not request that double tap be
+     * dispatched to the accessibility service, meaning that it will be handled by the framework and
+     * the view will be clicked.
      */
     @Test
     @AppModeFull
@@ -316,7 +320,11 @@
         mClickListener.assertNoneClicked();
     }
 
-    /** Test the case where we want to long click on the item that has accessibility focus. */
+    /**
+     * Test the case where we want to long click on the item that has accessibility focus. Note that
+     * this test does not request that double tap and hold be dispatched to the accessibility
+     * service, meaning that it will be handled by the framework and the view will be long clicked.
+     */
     @Test
     @AppModeFull
     public void testDoubleTapAndHoldAccessibilityFocus_performsLongClick() {
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 41201e3..1f8d45e 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -774,6 +774,11 @@
                 || message.contains("can only be called by the device owner"));
     }
 
+    private void assertOrganizationOwnedProfileOwnerMessage(String message) {
+        assertTrue("message is: "+ message,
+                message.contains("is not the profile owner on organization-owned device"));
+    }
+
     private void assertDeviceOwnerOrManageUsersMessage(String message) {
         assertTrue("message is: "+ message, message.contains("does not own the device")
                 || message.contains("can only be called by the device owner")
@@ -811,16 +816,16 @@
         }
     }
 
-    public void testSetSystemUpdatePolicy_failIfNotDeviceOwner() {
+    public void testSetSystemUpdatePolicy_failIfNotOrganizationOwnedProfileOwner() {
         if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetSystemUpdatePolicy_failIfNotDeviceOwner");
+            Log.w(TAG, "Skipping testSetSystemUpdatePolicy_failIfNotOrganizationOwnedProfileOwner");
             return;
         }
         try {
             mDevicePolicyManager.setSystemUpdatePolicy(mComponent, null);
             fail("did not throw expected SecurityException");
         } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
+            assertOrganizationOwnedProfileOwnerMessage(e.getMessage());
         }
     }
 
diff --git a/tests/app/src/android/app/cts/ActivityManagerApi29Test.java b/tests/app/src/android/app/cts/ActivityManagerApi29Test.java
index 4c56d1c..71d81da 100644
--- a/tests/app/src/android/app/cts/ActivityManagerApi29Test.java
+++ b/tests/app/src/android/app/cts/ActivityManagerApi29Test.java
@@ -40,6 +40,7 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 
+import androidx.test.filters.Suppress;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -61,6 +62,7 @@
  * one of the foreground state (including foreground_service state), this operation will be denied
  * when the process is in background state.
  */
+@Suppress
 @RunWith(AndroidJUnit4.class)
 public class ActivityManagerApi29Test {
     private static final String PACKAGE_NAME = "android.app.cts.activitymanager.api29";
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index ac50181..1251cda 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -54,6 +54,7 @@
 import android.os.SystemClock;
 import android.permission.cts.PermissionUtils;
 import android.server.wm.WindowManagerState;
+import androidx.test.filters.Suppress;
 import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiSelector;
@@ -1725,6 +1726,7 @@
      * PROCESS_CAPABILITY_FOREGROUND_LOCATION.
      * @throws Exception
      */
+    @Suppress
     public void testFgsLocation() throws Exception {
         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
                 PACKAGE_NAME_APP1, 0);
@@ -1787,6 +1789,7 @@
      * passed from client to service.
      * @throws Exception
      */
+    @Suppress
     public void testFgsLocationBind() throws Exception {
         setupWatchers(3);
 
@@ -1861,6 +1864,7 @@
      * Bound app should be TOP w/flag and BTOP without flag.
      * @throws Exception
      */
+    @Suppress
     public void testTopBind() throws Exception {
         setupWatchers(2);
 
diff --git a/tests/app/src/android/app/cts/UiModeManagerTest.java b/tests/app/src/android/app/cts/UiModeManagerTest.java
index 4dea1e4..77175c3 100644
--- a/tests/app/src/android/app/cts/UiModeManagerTest.java
+++ b/tests/app/src/android/app/cts/UiModeManagerTest.java
@@ -26,11 +26,12 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import androidx.test.filters.Suppress;
+
 import com.android.compatibility.common.util.BatteryUtils;
 import com.android.compatibility.common.util.SettingsUtils;
 
 import junit.framework.Assert;
-import org.junit.Ignore;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -38,6 +39,9 @@
 
 public class UiModeManagerTest extends AndroidTestCase {
     private static final String TAG = "UiModeManagerTest";
+    private static final long MAX_WAIT_TIME = 2 * 1000;
+
+    private static final long WAIT_TIME_INCR = 100;
 
     private UiModeManager mUiModeManager;
 
@@ -79,17 +83,19 @@
         }
     }
 
+    @Suppress //("b/146764875")
     public void testNightModeYesPersisted() throws InterruptedException {
+        // Reset the mode to no if it is set to another value
         setNightMode(UiModeManager.MODE_NIGHT_NO);
-        assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO);
 
         setNightMode(UiModeManager.MODE_NIGHT_YES);
         assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_YES);
     }
 
+    @Suppress //("b/146764875")
     public void testNightModeAutoPersisted() throws InterruptedException {
+        // Reset the mode to no if it is set to another value
         setNightMode(UiModeManager.MODE_NIGHT_NO);
-        assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO);
 
         setNightMode(UiModeManager.MODE_NIGHT_AUTO);
         assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_AUTO);
@@ -296,9 +302,18 @@
     }
 
     private void assertStoredNightModeSetting(int mode) {
+        int storedModeInt = -1;
         // Settings.Secure.UI_NIGHT_MODE
-        String storedMode = SettingsUtils.getSecureSetting("ui_night_mode");
-        int storedModeInt = Integer.parseInt(storedMode);
+        for (int i = 0; i < MAX_WAIT_TIME; i += WAIT_TIME_INCR) {
+            String storedMode = SettingsUtils.getSecureSetting("ui_night_mode");
+            storedModeInt = Integer.parseInt(storedMode);
+            if (mode == storedModeInt) break;
+            try {
+                Thread.sleep(WAIT_TIME_INCR);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
         assertEquals(mode, storedModeInt);
     }
 
diff --git a/tests/appsearch/src/com/android/cts/appsearch/AppSearchManagerTest.java b/tests/appsearch/src/com/android/cts/appsearch/AppSearchManagerTest.java
index c5389af..25ee503 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/AppSearchManagerTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/AppSearchManagerTest.java
@@ -17,8 +17,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.app.appsearch.AppSearch;
 import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchEmail;
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchSchema;
 import android.app.appsearch.AppSearchSchema.PropertyConfig;
@@ -66,11 +66,10 @@
     @Test
     public void testPutDocuments() throws Exception {
         // Schema registration
-        mAppSearch.setSchema(AppSearch.Email.SCHEMA);
+        mAppSearch.setSchema(AppSearchEmail.SCHEMA);
 
         // Index a document
-        AppSearch.Email email =
-                AppSearch.Email.newBuilder("uri1")
+        AppSearchEmail email = new AppSearchEmail.Builder("uri1")
                 .setFrom("from@example.com")
                 .setTo("to1@example.com", "to2@example.com")
                 .setSubject("testPut example")
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
index 82912f0..c9434cb 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
@@ -50,7 +50,8 @@
     private final InlinePresentation mInlinePresentation = new InlinePresentation(
             new Slice.Builder(new Uri.Builder().appendPath("DatasetTest").build(),
                     new SliceSpec("DatasetTest", 1)).build(),
-            new InlinePresentationSpec.Builder(new Size(10, 10), new Size(50, 50)).build());
+            new InlinePresentationSpec.Builder(new Size(10, 10),
+                    new Size(50, 50)).build(), /* pinned= */ false);
 
     private final RemoteViews mPresentation = mock(RemoteViews.class);
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 73e3828..01d9a1e2 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -2519,6 +2519,17 @@
                     CaptureRequest.DISTORTION_CORRECTION_MODE_OFF);
         }
 
+        // Scaler settings
+        if (mStaticInfo.areKeysAvailable(
+                CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES)) {
+            List<Integer> rotateAndCropModes = Arrays.asList(toObject(
+                props.get(CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES)));
+            if (rotateAndCropModes.contains(SCALER_ROTATE_AND_CROP_AUTO)) {
+                mCollector.expectKeyValueEquals(request, SCALER_ROTATE_AND_CROP,
+                        CaptureRequest.SCALER_ROTATE_AND_CROP_AUTO);
+            }
+        }
+
         // TODO: use the list of keys from CameraCharacteristics to avoid expecting
         //       keys which are not available by this CameraDevice.
     }
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index d7556f3..8f9f44b 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -42,6 +42,7 @@
 import android.os.ParcelFileDescriptor;
 import android.test.AndroidTestCase;
 import android.util.Log;
+import android.util.Pair;
 import androidx.test.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.PropertyUtil;
@@ -62,6 +63,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.Set;
 
 /**
  * <p>Basic test for CameraManager class.</p>
@@ -72,6 +74,7 @@
     private static final String TAG = "CameraManagerTest";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     private static final int NUM_CAMERA_REOPENS = 10;
+    private static final int AVAILABILITY_TIMEOUT_MS = 10;
 
     private PackageManager mPackageManager;
     private NoopCameraListener mListener;
@@ -576,13 +579,32 @@
         testCameraManagerListenerCallbacks(/*useExecutor*/ true);
     }
 
+    private <T> void verifyAvailabilityCbsReceived(HashSet<T> expectedCameras,
+            LinkedBlockingQueue<T> queue, LinkedBlockingQueue<T> otherQueue,
+            boolean available) throws Exception {
+        while (expectedCameras.size() > 0) {
+            T id = queue.poll(AVAILABILITY_TIMEOUT_MS,
+                    java.util.concurrent.TimeUnit.MILLISECONDS);
+            assertTrue("Did not receive initial " + (available ? "available" : "unavailable")
+                    + " notices for some cameras", id != null);
+            expectedCameras.remove(id);
+        }
+        // Verify no unavailable/available cameras were reported
+        assertTrue("Some camera devices are initially " + (available ? "unavailable" : "available"),
+                otherQueue.size() == 0);
+    }
+
     private void testCameraManagerListenerCallbacks(boolean useExecutor) throws Exception {
-        final int AVAILABILITY_TIMEOUT_MS = 10;
 
         final LinkedBlockingQueue<String> availableEventQueue = new LinkedBlockingQueue<>();
         final LinkedBlockingQueue<String> unavailableEventQueue = new LinkedBlockingQueue<>();
         final Executor executor = useExecutor ? new HandlerExecutor(mHandler) : null;
 
+        final LinkedBlockingQueue<Pair<String, String>> availablePhysicalCamEventQueue =
+                new LinkedBlockingQueue<>();
+        final LinkedBlockingQueue<Pair<String, String>> unavailablePhysicalCamEventQueue =
+                new LinkedBlockingQueue<>();
+
         CameraManager.AvailabilityCallback ac = new CameraManager.AvailabilityCallback() {
             @Override
             public void onCameraAvailable(String cameraId) {
@@ -604,6 +626,16 @@
             public void onCameraUnavailable(String cameraId) {
                 unavailableEventQueue.offer(cameraId);
             }
+
+            @Override
+            public void onPhysicalCameraAvailable(String cameraId, String physicalCameraId) {
+                availablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId));
+            }
+
+            @Override
+            public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) {
+                unavailablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId));
+            }
         };
 
         if (useExecutor) {
@@ -620,22 +652,18 @@
 
         // Verify we received available for all cameras' initial state in a reasonable amount of time
         HashSet<String> expectedAvailableCameras = new HashSet<String>(Arrays.asList(cameras));
-        while (expectedAvailableCameras.size() > 0) {
-            String id = availableEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
-                    java.util.concurrent.TimeUnit.MILLISECONDS);
-            assertTrue("Did not receive initial availability notices for some cameras",
-                       id != null);
-            expectedAvailableCameras.remove(id);
-        }
-        // Verify no unavailable cameras were reported
-        assertTrue("Some camera devices are initially unavailable",
-                unavailableEventQueue.size() == 0);
+        verifyAvailabilityCbsReceived(expectedAvailableCameras, availableEventQueue,
+                unavailableEventQueue, true /*available*/);
 
         // Verify transitions for individual cameras
         for (String id : cameras) {
             MockStateCallback mockListener = MockStateCallback.mock();
             mCameraListener = new BlockingStateCallback(mockListener);
 
+            // Clear logical camera callback queue in case the initial state of certain physical
+            // cameras are unavailable.
+            unavailablePhysicalCamEventQueue.clear();
+
             if (useExecutor) {
                 mCameraManager.openCamera(id, executor, mCameraListener);
             } else {
@@ -657,6 +685,23 @@
             assertTrue("Availability events received unexpectedly",
                     availableEventQueue.size() == 0);
 
+            // Verify that we see the expected 'unavailable' events if this camera is a physical
+            // camera of another logical multi-camera
+            HashSet<Pair<String, String>> relatedLogicalCameras = new HashSet<>();
+            for (String multiCamId : cameras) {
+                CameraCharacteristics props = mCameraManager.getCameraCharacteristics(multiCamId);
+                Set<String> physicalIds = props.getPhysicalCameraIds();
+                if (physicalIds.contains(id)) {
+                    relatedLogicalCameras.add(new Pair<String, String>(multiCamId, id));
+                }
+            }
+
+            HashSet<Pair<String, String>> expectedLogicalCameras =
+                    new HashSet<>(relatedLogicalCameras);
+            verifyAvailabilityCbsReceived(expectedLogicalCameras,
+                    unavailablePhysicalCamEventQueue, availablePhysicalCamEventQueue,
+                    false /*available*/);
+
             // Verify that we see the expected 'available' event after closing the camera
 
             camera.close();
@@ -672,6 +717,10 @@
             assertTrue("Unavailability events received unexpectedly",
                     unavailableEventQueue.size() == 0);
 
+            expectedLogicalCameras = new HashSet<Pair<String, String>>(relatedLogicalCameras);
+            verifyAvailabilityCbsReceived(expectedLogicalCameras,
+                    availablePhysicalCamEventQueue, unavailablePhysicalCamEventQueue,
+                    true /*available*/);
         }
 
         // Verify that we can unregister the listener and see no more events
@@ -718,7 +767,15 @@
                             candidateId),
                     candidateId == null);
 
+            Pair<String, String> candidatePhysicalIds = unavailablePhysicalCamEventQueue.poll(
+                    AVAILABILITY_TIMEOUT_MS, java.util.concurrent.TimeUnit.MILLISECONDS);
+            assertTrue("Received unavailability physical camera notice unexpectedly ",
+                    candidatePhysicalIds == null);
 
+            candidatePhysicalIds = availablePhysicalCamEventQueue.poll(
+                    AVAILABILITY_TIMEOUT_MS, java.util.concurrent.TimeUnit.MILLISECONDS);
+            assertTrue("Received availability notice for physical camera unexpectedly ",
+                    candidatePhysicalIds == null);
         }
 
     } // testCameraManagerListenerCallbacks
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index cf48aa4..6c304d7 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -987,6 +987,7 @@
         resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
         resultKeys.add(CaptureResult.REQUEST_PIPELINE_DEPTH);
         resultKeys.add(CaptureResult.SCALER_CROP_REGION);
+        resultKeys.add(CaptureResult.SCALER_ROTATE_AND_CROP);
         resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
         resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
         resultKeys.add(CaptureResult.SENSOR_SENSITIVITY);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 09079a6..30dba3e 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -2315,6 +2315,53 @@
         }
     }
 
+    /**
+     * Check rotate-and-crop camera reporting.
+     * Every device must report NONE; if actually supporting feature, must report NONE, 90, AUTO at
+     * least.
+     */
+    @Test
+    public void testRotateAndCropCharacteristics() {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            Log.i(TAG, "testRotateAndCropCharacteristics: Testing camera ID " + mAllCameraIds[i]);
+
+            CameraCharacteristics c = mCharacteristics.get(i);
+
+            if (!arrayContains(mCameraIdsUnderTest, mAllCameraIds[i])) {
+                // Skip hidden physical cameras
+                continue;
+            }
+
+            int[] availableRotateAndCropModes = c.get(
+                    CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
+            assertTrue("availableRotateAndCropModes must not be null",
+                     availableRotateAndCropModes != null);
+            boolean foundAuto = false;
+            boolean foundNone = false;
+            boolean found90 = false;
+            for (int mode :  availableRotateAndCropModes) {
+                switch(mode) {
+                    case CameraCharacteristics.SCALER_ROTATE_AND_CROP_NONE:
+                        foundNone = true;
+                        break;
+                    case CameraCharacteristics.SCALER_ROTATE_AND_CROP_90:
+                        found90 = true;
+                        break;
+                    case CameraCharacteristics.SCALER_ROTATE_AND_CROP_AUTO:
+                        foundAuto = true;
+                        break;
+                }
+            }
+            if (availableRotateAndCropModes.length > 1) {
+                assertTrue("To support SCALER_ROTATE_AND_CROP: NONE, 90, and AUTO must be included",
+                        foundNone && found90 && foundAuto);
+            } else {
+                assertTrue("If only one SCALER_ROTATE_AND_CROP value is supported, it must be NONE",
+                        foundNone);
+            }
+        }
+    }
+
     private boolean matchParametersToCharacteritics(Camera.Parameters params,
             Camera.CameraInfo info, CameraCharacteristics ch) {
         Integer facing = ch.get(CameraCharacteristics.LENS_FACING);
diff --git a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
index 27e6492..b8dc868 100644
--- a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
@@ -48,6 +48,7 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 import android.util.SizeF;
@@ -61,7 +62,9 @@
 
 import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -711,6 +714,29 @@
      */
     @Test
     public void testActivePhysicalId() throws Exception {
+        final int AVAILABILITY_TIMEOUT_MS = 10;
+        final LinkedBlockingQueue<Pair<String, String>> unavailablePhysicalCamEventQueue =
+                new LinkedBlockingQueue<>();
+        CameraManager.AvailabilityCallback ac = new CameraManager.AvailabilityCallback() {
+             @Override
+            public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) {
+                unavailablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId));
+            }
+        };
+
+        mCameraManager.registerAvailabilityCallback(ac, mHandler);
+        Set<Pair<String, String>> unavailablePhysicalCameras = new HashSet<Pair<String, String>>();
+        Pair<String, String> candidatePhysicalIds =
+                unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
+                java.util.concurrent.TimeUnit.MILLISECONDS);
+        while (candidatePhysicalIds != null) {
+            unavailablePhysicalCameras.add(candidatePhysicalIds);
+            candidatePhysicalIds =
+                unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
+                java.util.concurrent.TimeUnit.MILLISECONDS);
+        }
+        mCameraManager.unregisterAvailabilityCallback(ac);
+
         for (String id : mCameraIdsUnderTest) {
             try {
                 Log.i(TAG, "Testing Camera " + id);
@@ -777,10 +803,18 @@
                         }
                     }
                 }
+
+                // Query unavailable physical cameras, and make sure the active physical id
+                // isn't an unavailable physical camera.
+                for (Pair<String, String> unavailPhysicalCamera: unavailablePhysicalCameras) {
+                    assertFalse(unavailPhysicalCamera.first.equals(id) &&
+                           unavailPhysicalCamera.second.equals(storedActiveId));
+                }
             } finally {
                 closeDevice();
             }
         }
+
     }
 
     /**
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index 918daeb..101d2e1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -55,6 +55,8 @@
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -174,6 +176,29 @@
      */
     @Test
     public void testMandatoryOutputCombinations() throws Exception {
+        final int AVAILABILITY_TIMEOUT_MS = 10;
+        final LinkedBlockingQueue<Pair<String, String>> unavailablePhysicalCamEventQueue =
+                new LinkedBlockingQueue<>();
+        CameraManager.AvailabilityCallback ac = new CameraManager.AvailabilityCallback() {
+             @Override
+            public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) {
+                unavailablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId));
+            }
+        };
+
+        mCameraManager.registerAvailabilityCallback(ac, mHandler);
+        Set<Pair<String, String>> unavailablePhysicalCameras = new HashSet<Pair<String, String>>();
+        Pair<String, String> candidatePhysicalIds =
+                unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
+                java.util.concurrent.TimeUnit.MILLISECONDS);
+        while (candidatePhysicalIds != null) {
+            unavailablePhysicalCameras.add(candidatePhysicalIds);
+            candidatePhysicalIds =
+                unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
+                java.util.concurrent.TimeUnit.MILLISECONDS);
+        }
+        mCameraManager.unregisterAvailabilityCallback(ac);
+
         for (String id : mCameraIdsUnderTest) {
             openDevice(id);
             MandatoryStreamCombination[] combinations =
@@ -204,6 +229,13 @@
                             // its stream combination through logical camera.
                             continue;
                         }
+                        for (Pair<String, String> unavailPhysicalCam : unavailablePhysicalCameras) {
+                            if (unavailPhysicalCam.first.equals(id) ||
+                                    unavailPhysicalCam.second.equals(physicalId)) {
+                                // This particular physical camera isn't available. Skip.
+                                continue;
+                            }
+                        }
                         StaticMetadata physicalStaticInfo = mAllStaticInfo.get(physicalId);
                         MandatoryStreamCombination[] phyCombinations =
                                 physicalStaticInfo.getCharacteristics().get(
diff --git a/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
index 6fd9173..789626a 100644
--- a/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
@@ -88,6 +88,22 @@
                             cameraId);
                     Log.i(TAG, "Camera " + cameraId + " is unavailable");
                 }
+
+                @Override
+                public void onPhysicalCameraAvailable(String cameraId, String physicalCameraId) {
+                    super.onPhysicalCameraAvailable(cameraId, physicalCameraId);
+                    mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_AVAILABLE,
+                            cameraId + " : " + physicalCameraId);
+                    Log.i(TAG, "Camera " + cameraId + " : " + physicalCameraId + " is available");
+                }
+
+                @Override
+                public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) {
+                    super.onPhysicalCameraUnavailable(cameraId, physicalCameraId);
+                    mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_UNAVAILABLE,
+                            cameraId + " : " + physicalCameraId);
+                    Log.i(TAG, "Camera " + cameraId + " : " + physicalCameraId + " is unavailable");
+                }
             }, null);
 
             final String chosen = cameraIds[0];
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/BroadcastReceiverActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/BroadcastReceiverActivity.java
index c967a32..b3ab326 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/BroadcastReceiverActivity.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/BroadcastReceiverActivity.java
@@ -42,21 +42,28 @@
 import android.view.ViewGroup;
 import android.view.Window;
 
+import java.lang.ref.WeakReference;
+
 /**
  * Activity that registers broadcast receiver .
  */
 public class BroadcastReceiverActivity extends Activity {
     private static final String TAG = BroadcastReceiverActivity.class.getSimpleName();
 
-    private TestBroadcastReceiver mBroadcastReceiver = new TestBroadcastReceiver();
+    private TestBroadcastReceiver mBroadcastReceiver;
 
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        IntentFilter broadcastFilter = new IntentFilter(ACTION_TRIGGER_BROADCAST);
-
-        registerReceiver(mBroadcastReceiver, broadcastFilter);
+        final Object receiver = getLastNonConfigurationInstance();
+        if (receiver instanceof TestBroadcastReceiver) {
+            mBroadcastReceiver = (TestBroadcastReceiver) receiver;
+            mBroadcastReceiver.associate(this);
+        } else {
+            mBroadcastReceiver = new TestBroadcastReceiver(this);
+            mBroadcastReceiver.register();
+        }
 
         // Determine if a display cutout is present
         final View view = new View(this);
@@ -79,38 +86,79 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
-
-        unregisterReceiver(mBroadcastReceiver);
+        mBroadcastReceiver.destroy();
     }
 
-    public class TestBroadcastReceiver extends BroadcastReceiver {
+    @Override
+    public Object onRetainNonConfigurationInstance() {
+        return mBroadcastReceiver;
+    }
+
+    /**
+     * The receiver to perform action on the associated activity. If a broadcast intent is received
+     * while the activity is relaunching, it will be handled after the activity is recreated.
+     */
+    private static class TestBroadcastReceiver extends BroadcastReceiver {
+        final Context mAppContext;
+        WeakReference<Activity> mRef;
+
+        TestBroadcastReceiver(Activity activity) {
+            mAppContext = activity.getApplicationContext();
+            associate(activity);
+        }
+
+        void register() {
+            mAppContext.registerReceiver(this, new IntentFilter(ACTION_TRIGGER_BROADCAST));
+        }
+
+        void associate(Activity activity) {
+            mRef = new WeakReference<>(activity);
+        }
+
+        void destroy() {
+            final Activity activity = mRef != null ? mRef.get() : null;
+            if (activity != null && activity.isChangingConfigurations()) {
+                // The activity is destroyed for configuration change. Because it will be recreated
+                // immediately the receiver only needs to associate to the new instance.
+                return;
+            }
+            // The case of real finish.
+            mAppContext.unregisterReceiver(this);
+        }
+
         @Override
         public void onReceive(Context context, Intent intent) {
             final Bundle extras = intent.getExtras();
-            Log.i(TAG, "onReceive: extras=" + extras);
-
             if (extras == null) {
                 return;
             }
+            // Trigger unparcel so the log can show the content of extras.
+            extras.size();
+            Log.i(TAG, "onReceive: extras=" + extras);
+
+            final Activity activity = mRef.get();
+            if (activity == null) {
+                return;
+            }
+
             if (extras.getBoolean(EXTRA_FINISH_BROADCAST)) {
-                finish();
+                activity.finish();
             }
             if (extras.getBoolean(EXTRA_MOVE_BROADCAST_TO_BACK)) {
-                moveTaskToBack(true);
+                activity.moveTaskToBack(true);
             }
             if (extras.containsKey(EXTRA_BROADCAST_ORIENTATION)) {
-                setRequestedOrientation(extras.getInt(EXTRA_BROADCAST_ORIENTATION));
+                activity.setRequestedOrientation(extras.getInt(EXTRA_BROADCAST_ORIENTATION));
             }
             if (extras.getBoolean(EXTRA_DISMISS_KEYGUARD)) {
-                getWindow().addFlags(FLAG_DISMISS_KEYGUARD);
+                activity.getWindow().addFlags(FLAG_DISMISS_KEYGUARD);
             }
             if (extras.getBoolean(EXTRA_DISMISS_KEYGUARD_METHOD)) {
-                getSystemService(KeyguardManager.class).requestDismissKeyguard(
-                        BroadcastReceiverActivity.this,
+                activity.getSystemService(KeyguardManager.class).requestDismissKeyguard(activity,
                         new KeyguardDismissLoggerCallback(context, BROADCAST_RECEIVER_ACTIVITY));
             }
 
-            ActivityLauncher.launchActivityFromExtras(BroadcastReceiverActivity.this, extras);
+            ActivityLauncher.launchActivityFromExtras(activity, extras);
         }
     }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
index 67cabaa..459eda4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
@@ -21,6 +21,7 @@
 import static android.server.wm.dndsourceapp.Components.DRAG_SOURCE;
 import static android.server.wm.dndtargetapp.Components.DROP_TARGET;
 import static android.server.wm.dndtargetappsdk23.Components.DROP_TARGET_SDK23;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -142,6 +143,8 @@
         Point topLeft = new Point(leftSide ? 0 : displaySize.x / 2, 0);
         Point bottomRight = new Point(leftSide ? displaySize.x / 2 : displaySize.x, displaySize.y);
         resizeActivityTask(componentName, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
+        waitAndAssertTopResumedActivity(componentName, DEFAULT_DISPLAY,
+                "Activity launched as freeform should be resumed");
     }
 
     private void injectInput(Point from, Point to, int steps) throws Exception {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
index c4e7e94..db3c78c 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
@@ -509,14 +509,15 @@
         mAmWmState.assertKeyguardShowingAndNotOccluded();
     }
 
-    @Test
-    /*
-      Turn on keyguard, and launch an activity on top of the keyguard.
-      Next, change the orientation of the device to rotate the activity.
-      The activity should still remain above keyguard at this point.
-      Send the 'finish' broadcast to dismiss the activity.
-      Ensure that the activity is gone, and the keyguard is visible.
+
+    /**
+     * Turn on keyguard, and launch an activity on top of the keyguard.
+     * Next, change the orientation of the device to rotate the activity.
+     * The activity should still remain above keyguard at this point.
+     * Send the 'finish' broadcast to dismiss the activity.
+     * Ensure that the activity is gone, and the keyguard is visible.
      */
+    @Test
     public void testUnoccludedRotationChange() {
         // Go home now to make sure Home is behind Keyguard.
         launchHomeActivity();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index 231b8ee..3338584 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -214,60 +214,6 @@
         mAmWmState.assertVisibility(PIP_ACTIVITY, true);
     }
 
-    @Test
-    public void testPinnedStackDefaultBounds() {
-        // Launch a PIP activity
-        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
-        // Wait for animation complete since we are comparing bounds
-        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-
-        final RotationSession rotationSession = createManagedRotationSession();
-        rotationSession.set(ROTATION_0);
-        waitForValidPinnedStackBounds(WindowManagerState::getDefaultPinnedStackBounds);
-        WindowManagerState wmState = mAmWmState.getWmState();
-        wmState.computeState();
-        Rect defaultPipBounds = wmState.getDefaultPinnedStackBounds();
-        Rect stableBounds = wmState.getStableBounds();
-        assertTrue(defaultPipBounds.width() > 0 && defaultPipBounds.height() > 0);
-        assertTrue(stableBounds.contains(defaultPipBounds));
-
-        rotationSession.set(ROTATION_90);
-        waitForValidPinnedStackBounds(WindowManagerState::getDefaultPinnedStackBounds);
-        wmState = mAmWmState.getWmState();
-        wmState.computeState();
-        defaultPipBounds = wmState.getDefaultPinnedStackBounds();
-        stableBounds = wmState.getStableBounds();
-        assertTrue(defaultPipBounds.width() > 0 && defaultPipBounds.height() > 0);
-        assertTrue(stableBounds.contains(defaultPipBounds));
-    }
-
-    @Test
-    public void testPinnedStackMovementBounds() {
-        // Launch a PIP activity
-        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
-        // Wait for animation complete since we are comparing bounds
-        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-
-        final RotationSession rotationSession = createManagedRotationSession();
-        rotationSession.set(ROTATION_0);
-        waitForValidPinnedStackBounds(WindowManagerState::getPinnedStackMovementBounds);
-        WindowManagerState wmState = mAmWmState.getWmState();
-        wmState.computeState();
-        Rect pipMovementBounds = wmState.getPinnedStackMovementBounds();
-        Rect stableBounds = wmState.getStableBounds();
-        assertTrue(pipMovementBounds.width() > 0 && pipMovementBounds.height() > 0);
-        assertTrue(stableBounds.contains(pipMovementBounds));
-
-        rotationSession.set(ROTATION_90);
-        waitForValidPinnedStackBounds(WindowManagerState::getPinnedStackMovementBounds);
-        wmState = mAmWmState.getWmState();
-        wmState.computeState();
-        pipMovementBounds = wmState.getPinnedStackMovementBounds();
-        stableBounds = wmState.getStableBounds();
-        assertTrue(pipMovementBounds.width() > 0 && pipMovementBounds.height() > 0);
-        assertTrue(stableBounds.contains(pipMovementBounds));
-    }
-
     private void waitForValidPinnedStackBounds(Function<WindowManagerState, Rect> boundsFunc) {
         mAmWmState.waitForWithWmState(wmState -> {
             final Rect bounds = boundsFunc.apply(wmState);
@@ -1243,108 +1189,6 @@
                 finalAppSize);
     }
 
-    @FlakyTest(bugId = 145133340)
-    @Test
-    public void testEnterPictureInPictureSavePosition() throws Exception {
-        // Ensure we have static shelf offset by running this test over a non-home activity
-        launchActivity(NO_RELAUNCH_ACTIVITY);
-        mAmWmState.waitForActivityState(mAmWmState.getAmState().getHomeActivityName(),
-                STATE_STOPPED);
-
-        // Launch PiP activity with auto-enter PiP, save the default position of the PiP
-        // (while the PiP is still animating sleep)
-        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
-        // Wait for animation complete since we are comparing bounds
-        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-        assertPinnedStackExists();
-
-        // Move the PiP to a new position on screen
-        final Rect initialBounds = new Rect();
-        final Rect offsetBounds = new Rect();
-        offsetPipWithinMovementBounds(100 /* offsetY */, initialBounds, offsetBounds);
-
-        // Expand the PiP back to fullscreen and back into PiP and ensure that it is in the same
-        // position as before we expanded (and that the default bounds reflect that)
-        mBroadcastActionTrigger.doAction(ACTION_EXPAND_PIP);
-        waitForExitPipToFullscreen(PIP_ACTIVITY);
-        mBroadcastActionTrigger.doAction(ACTION_ENTER_PIP);
-        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-        mAmWmState.computeState(true);
-        // Due to rounding in how we save and apply the snap fraction we may be a pixel off, so just
-        // account for that in this check
-        offsetBounds.inset(-1, -1);
-        assertTrue("Expected offsetBounds=" + offsetBounds + " to contain bounds="
-                + getPinnedStackBounds(), offsetBounds.contains(getPinnedStackBounds()));
-
-        // Expand the PiP, then launch an activity in a new task, and ensure that the PiP goes back
-        // to the default position (and not the saved position) the next time it is launched
-        mBroadcastActionTrigger.doAction(ACTION_EXPAND_PIP);
-        waitForExitPipToFullscreen(PIP_ACTIVITY);
-        launchActivity(TEST_ACTIVITY);
-        mBroadcastActionTrigger.doAction(TEST_ACTIVITY_ACTION_FINISH_SELF);
-        mAmWmState.waitForActivityState(PIP_ACTIVITY, STATE_RESUMED);
-        mAmWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
-        mBroadcastActionTrigger.doAction(ACTION_ENTER_PIP);
-        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-        assertPinnedStackExists();
-        assertTrue("Expected initialBounds=" + initialBounds + " to equal bounds="
-                + getPinnedStackBounds(), initialBounds.equals(getPinnedStackBounds()));
-    }
-
-    @Test
-    public void testEnterPictureInPictureDiscardSavedPositionOnFinish() throws Exception {
-        // Ensure we have static shelf offset by running this test over a non-home activity
-        launchActivity(NO_RELAUNCH_ACTIVITY);
-        mAmWmState.waitForActivityState(mAmWmState.getAmState().getHomeActivityName(),
-                STATE_STOPPED);
-
-        // Launch PiP activity with auto-enter PiP, save the default position of the PiP
-        // (while the PiP is still animating sleep)
-        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
-        // Wait for animation complete since we are comparing bounds
-        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-        assertPinnedStackExists();
-
-        // Move the PiP to a new position on screen
-        final Rect initialBounds = new Rect();
-        final Rect offsetBounds = new Rect();
-        offsetPipWithinMovementBounds(100 /* offsetY */, initialBounds, offsetBounds);
-
-        // Finish the activity
-        mBroadcastActionTrigger.doAction(ACTION_FINISH);
-        waitForPinnedStackRemoved();
-        assertPinnedStackDoesNotExist();
-
-        // Ensure that starting the same PiP activity after it finished will go to the default
-        // bounds
-        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
-        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-        assertPinnedStackExists();
-        assertTrue("Expected initialBounds=" + initialBounds + " to equal bounds="
-                + getPinnedStackBounds(), initialBounds.equals(getPinnedStackBounds()));
-    }
-
-    /**
-     * Offsets the PiP in a direction by {@param offsetY} such that it is still within the movement
-     * bounds.
-     */
-    private void offsetPipWithinMovementBounds(int offsetY, Rect initialBoundsOut,
-            Rect offsetBoundsOut) {
-        final ActivityStack stack = getPinnedStack();
-        final Rect displayRect = mAmWmState.getWmState().getDisplay(stack.mDisplayId)
-                .getDisplayRect();
-        initialBoundsOut.set(getPinnedStackBounds());
-        offsetBoundsOut.set(initialBoundsOut);
-        if (initialBoundsOut.top < displayRect.centerY()) {
-            // If the default gravity is top-aligned, offset down instead of up
-            offsetBoundsOut.offset(0, offsetY);
-        } else {
-            offsetBoundsOut.offset(0, -offsetY);
-        }
-        resizePinnedStack(stack.mStackId, offsetBoundsOut.left, offsetBoundsOut.top,
-                offsetBoundsOut.right, offsetBoundsOut.bottom);
-    }
-
     /** Get app bounds in last applied configuration. */
     private Rect getAppBounds(ComponentName activityName) {
         final Configuration config = TestJournalContainer.get(activityName).extras
@@ -1374,29 +1218,6 @@
     }
 
     /**
-     * Asserts that the pinned stack bounds does not intersect with the IME bounds.
-     */
-    private void assertPinnedStackDoesNotIntersectIME() {
-        // Ensure that the IME is visible
-        WindowManagerState wmState = mAmWmState.getWmState();
-        wmState.computeState();
-        WindowManagerState.WindowState imeWinState = wmState.getInputMethodWindowState();
-        assertTrue(imeWinState != null);
-
-        // Ensure that the PIP movement is constrained by the display bounds intersecting the
-        // non-IME bounds
-        Rect imeContentFrame = imeWinState.getContentFrame();
-        Rect imeContentInsets = imeWinState.getGivenContentInsets();
-        Rect imeBounds = new Rect(imeContentFrame.left + imeContentInsets.left,
-                imeContentFrame.top + imeContentInsets.top,
-                imeContentFrame.right - imeContentInsets.width(),
-                imeContentFrame.bottom - imeContentInsets.height());
-        wmState.computeState();
-        Rect pipMovementBounds = wmState.getPinnedStackMovementBounds();
-        assertTrue(!Rect.intersects(pipMovementBounds, imeBounds));
-    }
-
-    /**
      * Asserts that the pinned stack bounds is contained in the display bounds.
      */
     private void assertPinnedStackActivityIsInDisplayBounds(ComponentName activityName) {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
index 87b4902..bc9005f 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
@@ -49,7 +49,6 @@
 import com.android.server.wm.nano.DisplayContentProto;
 import com.android.server.wm.nano.DisplayFramesProto;
 import com.android.server.wm.nano.IdentifierProto;
-import com.android.server.wm.nano.PinnedStackControllerProto;
 import com.android.server.wm.nano.StackProto;
 import com.android.server.wm.nano.TaskProto;
 import com.android.server.wm.nano.WindowContainerProto;
@@ -122,8 +121,6 @@
     private String mFocusedApp = null;
     private int mFocusedDisplayId = DEFAULT_DISPLAY;
     private String mInputMethodWindowAppToken = null;
-    private Rect mDefaultPinnedStackBounds = new Rect();
-    private Rect mPinnedStackMovementBounds = new Rect();
     private final LinkedList<String> mSysDump = new LinkedList();
     private int mRotation;
     private int mLastOrientation;
@@ -218,11 +215,6 @@
                     mIsDockedStackMinimized =
                             displayProto.dockedStackDividerController.minimizedDock;
                 }
-                PinnedStackControllerProto pinnedStackProto = displayProto.pinnedStackController;
-                if (pinnedStackProto != null) {
-                    mDefaultPinnedStackBounds = extract(pinnedStackProto.defaultBounds);
-                    mPinnedStackMovementBounds = extract(pinnedStackProto.movementBounds);
-                }
             }
         }
         for (WindowState w : allWindows) {
@@ -556,14 +548,6 @@
         return getDisplay(DEFAULT_DISPLAY).mStableBounds;
     }
 
-    Rect getDefaultPinnedStackBounds() {
-        return new Rect(mDefaultPinnedStackBounds);
-    }
-
-    Rect getPinnedStackMovementBounds() {
-        return new Rect(mPinnedStackMovementBounds);
-    }
-
     WindowState findFirstWindowWithType(int type) {
         for (WindowState window : mWindowStates) {
             if (window.getType() == type) {
@@ -595,8 +579,6 @@
         mFocusedApp = null;
         mInputMethodWindowAppToken = null;
         mIsDockedStackMinimized = false;
-        mDefaultPinnedStackBounds.setEmpty();
-        mPinnedStackMovementBounds.setEmpty();
         mRotation = 0;
         mLastOrientation = 0;
         mFocusedDisplayId = DEFAULT_DISPLAY;
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GnssClockTest.java b/tests/location/location_fine/src/android/location/cts/fine/GnssClockTest.java
index 7863675..0937da4 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GnssClockTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GnssClockTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.location.GnssClock;
+import android.location.GnssStatus;
 import android.os.Parcel;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -81,6 +82,14 @@
         clock.resetDriftUncertaintyNanosPerSecond();
         assertFalse(clock.hasDriftUncertaintyNanosPerSecond());
 
+        assertTrue(clock.hasElapsedRealtimeNanos());
+        clock.resetElapsedRealtimeNanos();
+        assertFalse(clock.hasElapsedRealtimeNanos());
+
+        assertTrue(clock.hasElapsedRealtimeUncertaintyNanos());
+        clock.resetElapsedRealtimeUncertaintyNanos();
+        assertFalse(clock.hasElapsedRealtimeUncertaintyNanos());
+
         assertTrue(clock.hasFullBiasNanos());
         clock.resetFullBiasNanos();
         assertFalse(clock.hasFullBiasNanos());
@@ -89,17 +98,21 @@
         clock.resetLeapSecond();
         assertFalse(clock.hasLeapSecond());
 
+        assertTrue(clock.hasReferenceConstellationTypeForIsb());
+        clock.resetReferenceConstellationTypeForIsb();
+        assertFalse(clock.hasReferenceConstellationTypeForIsb());
+
+        assertTrue(clock.hasReferenceCarrierFrequencyHzForIsb());
+        clock.resetReferenceCarrierFrequencyHzForIsb();
+        assertFalse(clock.hasReferenceCarrierFrequencyHzForIsb());
+
+        assertTrue(clock.hasReferenceCodeTypeForIsb());
+        clock.resetReferenceCodeTypeForIsb();
+        assertFalse(clock.hasReferenceCodeTypeForIsb());
+
         assertTrue(clock.hasTimeUncertaintyNanos());
         clock.resetTimeUncertaintyNanos();
         assertFalse(clock.hasTimeUncertaintyNanos());
-
-        assertTrue(clock.hasElapsedRealtimeNanos());
-        clock.resetElapsedRealtimeNanos();
-        assertFalse(clock.hasElapsedRealtimeNanos());
-
-        assertTrue(clock.hasElapsedRealtimeUncertaintyNanos());
-        clock.resetElapsedRealtimeUncertaintyNanos();
-        assertFalse(clock.hasElapsedRealtimeUncertaintyNanos());
     }
 
     private static void setTestValues(GnssClock clock) {
@@ -107,13 +120,16 @@
         clock.setBiasUncertaintyNanos(2.0);
         clock.setDriftNanosPerSecond(3.0);
         clock.setDriftUncertaintyNanosPerSecond(4.0);
+        clock.setElapsedRealtimeNanos(10987732253L);
+        clock.setElapsedRealtimeUncertaintyNanos(3943523.0);
         clock.setFullBiasNanos(5);
         clock.setHardwareClockDiscontinuityCount(6);
         clock.setLeapSecond(7);
+        clock.setReferenceConstellationTypeForIsb(GnssStatus.CONSTELLATION_GPS);
+        clock.setReferenceCarrierFrequencyHzForIsb(1.59975e+09);
+        clock.setReferenceCodeTypeForIsb("C");
         clock.setTimeNanos(8);
         clock.setTimeUncertaintyNanos(9.0);
-        clock.setElapsedRealtimeNanos(10987732253L);
-        clock.setElapsedRealtimeUncertaintyNanos(3943523.0);
     }
 
     private static void verifyTestValues(GnssClock clock) {
@@ -121,12 +137,15 @@
         assertEquals(2.0, clock.getBiasUncertaintyNanos(), DELTA);
         assertEquals(3.0, clock.getDriftNanosPerSecond(), DELTA);
         assertEquals(4.0, clock.getDriftUncertaintyNanosPerSecond(), DELTA);
+        assertEquals(10987732253L, clock.getElapsedRealtimeNanos());
+        assertEquals(3943523.0, clock.getElapsedRealtimeUncertaintyNanos(), DELTA);
         assertEquals(5, clock.getFullBiasNanos());
         assertEquals(6, clock.getHardwareClockDiscontinuityCount());
         assertEquals(7, clock.getLeapSecond());
+        assertEquals(GnssStatus.CONSTELLATION_GPS, clock.getReferenceConstellationTypeForIsb());
+        assertEquals(1.59975e+09, clock.getReferenceCarrierFrequencyHzForIsb(), DELTA);
+        assertEquals("C", clock.getReferenceCodeTypeForIsb());
         assertEquals(8, clock.getTimeNanos());
         assertEquals(9.0, clock.getTimeUncertaintyNanos(), DELTA);
-        assertEquals(10987732253L, clock.getElapsedRealtimeNanos());
-        assertEquals(3943523.0, clock.getElapsedRealtimeUncertaintyNanos(), DELTA);
     }
 }
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java b/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java
index 5c318a3..dccf022 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java
@@ -99,6 +99,22 @@
         assertTrue(measurement.hasBasebandCn0DbHz());
         measurement.resetBasebandCn0DbHz();
         assertFalse(measurement.hasBasebandCn0DbHz());
+
+        assertTrue(measurement.hasReceiverInterSignalBiasNanos());
+        measurement.resetReceiverInterSignalBiasNanos();
+        assertFalse(measurement.hasReceiverInterSignalBiasNanos());
+
+        assertTrue(measurement.hasReceiverInterSignalBiasUncertaintyNanos());
+        measurement.resetReceiverInterSignalBiasUncertaintyNanos();
+        assertFalse(measurement.hasReceiverInterSignalBiasUncertaintyNanos());
+
+        assertTrue(measurement.hasSatelliteInterSignalBiasNanos());
+        measurement.resetSatelliteInterSignalBiasNanos();
+        assertFalse(measurement.hasSatelliteInterSignalBiasNanos());
+
+        assertTrue(measurement.hasSatelliteInterSignalBiasUncertaintyNanos());
+        measurement.resetSatelliteInterSignalBiasUncertaintyNanos();
+        assertFalse(measurement.hasSatelliteInterSignalBiasUncertaintyNanos());
     }
 
     private static void setTestValues(GnssMeasurement measurement) {
@@ -118,6 +134,10 @@
         measurement.setPseudorangeRateUncertaintyMetersPerSecond(10.0);
         measurement.setReceivedSvTimeNanos(11);
         measurement.setReceivedSvTimeUncertaintyNanos(12);
+        measurement.setReceiverInterSignalBiasNanos(1.3);
+        measurement.setReceiverInterSignalBiasUncertaintyNanos(2.5);
+        measurement.setSatelliteInterSignalBiasNanos(5.4);
+        measurement.setSatelliteInterSignalBiasUncertaintyNanos(10.0);
         measurement.setSnrInDb(13.0);
         measurement.setState(14);
         measurement.setSvid(15);
@@ -142,6 +162,10 @@
         assertEquals(10.0, measurement.getPseudorangeRateUncertaintyMetersPerSecond(), DELTA);
         assertEquals(11, measurement.getReceivedSvTimeNanos());
         assertEquals(12, measurement.getReceivedSvTimeUncertaintyNanos());
+        assertEquals(1.3, measurement.getReceiverInterSignalBiasNanos(), DELTA);
+        assertEquals(2.5, measurement.getReceiverInterSignalBiasUncertaintyNanos(), DELTA);
+        assertEquals(5.4, measurement.getSatelliteInterSignalBiasNanos(), DELTA);
+        assertEquals(10.0, measurement.getSatelliteInterSignalBiasUncertaintyNanos(), DELTA);
         assertEquals(13.0, measurement.getSnrInDb(), DELTA);
         assertEquals(14, measurement.getState());
         assertEquals(15, measurement.getSvid());
diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
index 56f5ff1..58aa065 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
@@ -614,6 +614,7 @@
     }
 
     @Test
+    @AppModeFull(reason = "Instant apps can only receive whitelisted broadcasts")
     public void testListenProviderEnable_Broadcast() throws Exception {
         try (BroadcastCapture capture = new BroadcastCapture(mContext, PROVIDERS_CHANGED_ACTION)) {
             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
diff --git a/tests/media/Android.bp b/tests/media/Android.bp
index f01eef1..889b123 100644
--- a/tests/media/Android.bp
+++ b/tests/media/Android.bp
@@ -24,6 +24,9 @@
         "android.test.runner.stubs",
         "android.test.base.stubs",
     ],
+    jni_libs: [
+        "libctsmediav2muxer_jni",
+    ],
     srcs: ["src/**/*.java"],
     // Tag this module as a cts test artifact
     test_suites: [
diff --git a/tests/media/OWNERS b/tests/media/OWNERS
index 7367427..8ffa99e 100644
--- a/tests/media/OWNERS
+++ b/tests/media/OWNERS
@@ -1,2 +1,12 @@
-# Bug component:
-include /tests/tests/media/OWNERS
+# Bug component: 1344
+andrewlewis@google.com
+chz@google.com
+dwkang@google.com
+elaurent@google.com
+essick@google.com
+gkasten@google.com
+hunga@google.com
+jmtrivi@google.com
+lajos@google.com
+marcone@google.com
+wjia@google.com
diff --git a/tests/media/jni/Android.bp b/tests/media/jni/Android.bp
new file mode 100644
index 0000000..e151d37
--- /dev/null
+++ b/tests/media/jni/Android.bp
@@ -0,0 +1,31 @@
+// 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.
+
+cc_test_library {
+    name: "libctsmediav2muxer_jni",
+    srcs: [
+        "NativeMediaConstants.cpp",
+        "NativeMuxerTest.cpp",
+    ],
+    shared_libs: [
+        "libmediandk",
+        "liblog",
+    ],
+    stl: "libc++_static",
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    gtest: false,
+}
diff --git a/tests/media/jni/NativeMediaConstants.cpp b/tests/media/jni/NativeMediaConstants.cpp
new file mode 100644
index 0000000..a3867f9
--- /dev/null
+++ b/tests/media/jni/NativeMediaConstants.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#include "NativeMediaConstants.h"
+
+/* Note: constants used by the native media tests but not available in media ndk api */
+const char* AMEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
+const char* AMEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+const char* AMEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
+const char* AMEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
+const char* AMEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
+const char* AMEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
+
+const char* AMEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
+const char* AMEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
+const char* AMEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
+const char* AMEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
+const char* AMEDIA_MIMETYPE_AUDIO_OPUS = "audio/opus";
+
diff --git a/tests/media/jni/NativeMediaConstants.h b/tests/media/jni/NativeMediaConstants.h
new file mode 100644
index 0000000..5a94368
--- /dev/null
+++ b/tests/media/jni/NativeMediaConstants.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef MEDIACTSNATIVE_NATIVE_MEDIA_CONSTANTS_H
+#define MEDIACTSNATIVE_NATIVE_MEDIA_CONSTANTS_H
+
+extern const char* AMEDIA_MIMETYPE_VIDEO_VP8;
+extern const char* AMEDIA_MIMETYPE_VIDEO_VP9;
+extern const char* AMEDIA_MIMETYPE_VIDEO_AVC;
+extern const char* AMEDIA_MIMETYPE_VIDEO_HEVC;
+extern const char* AMEDIA_MIMETYPE_VIDEO_MPEG4;
+extern const char* AMEDIA_MIMETYPE_VIDEO_H263;
+
+extern const char* AMEDIA_MIMETYPE_AUDIO_AMR_NB;
+extern const char* AMEDIA_MIMETYPE_AUDIO_AMR_WB;
+extern const char* AMEDIA_MIMETYPE_AUDIO_AAC;
+extern const char* AMEDIA_MIMETYPE_AUDIO_VORBIS;
+extern const char* AMEDIA_MIMETYPE_AUDIO_OPUS;
+
+// TODO(b/146420990)
+typedef enum {
+    OUTPUT_FORMAT_START = 0,
+    OUTPUT_FORMAT_MPEG_4 = OUTPUT_FORMAT_START,
+    OUTPUT_FORMAT_WEBM = OUTPUT_FORMAT_START + 1,
+    OUTPUT_FORMAT_THREE_GPP = OUTPUT_FORMAT_START + 2,
+    OUTPUT_FORMAT_HEIF = OUTPUT_FORMAT_START + 3,
+    OUTPUT_FORMAT_OGG = OUTPUT_FORMAT_START + 4,
+    OUTPUT_FORMAT_LIST_END = OUTPUT_FORMAT_START + 4,
+} MuxerFormat;
+
+#endif  // MEDIACTSNATIVE_NATIVE_MEDIA_CONSTANTS_H
diff --git a/tests/media/jni/NativeMuxerTest.cpp b/tests/media/jni/NativeMuxerTest.cpp
new file mode 100644
index 0000000..f9adbd7
--- /dev/null
+++ b/tests/media/jni/NativeMuxerTest.cpp
@@ -0,0 +1,742 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeMuxerTest"
+#include <log/log.h>
+
+#include <fcntl.h>
+#include <jni.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <cmath>
+#include <cstring>
+#include <fstream>
+#include <map>
+#include <vector>
+
+#include "NativeMediaConstants.h"
+#include "media/NdkMediaExtractor.h"
+#include "media/NdkMediaFormat.h"
+#include "media/NdkMediaMuxer.h"
+
+/**
+ * MuxerNativeTestHelper breaks a media file to elements that a muxer can use to rebuild its clone.
+ * While testing muxer, if the test doesn't use MediaCodecs class to generate elementary stream,
+ * but uses MediaExtractor, this class will be handy
+ */
+class MuxerNativeTestHelper {
+  public:
+    explicit MuxerNativeTestHelper(const char* srcPath, const char* mime = nullptr,
+                                   int frameLimit = -1)
+        : mSrcPath(srcPath), mMime(mime), mTrackCount(0), mBuffer(nullptr) {
+        mFrameLimit = frameLimit < 0 ? INT_MAX : frameLimit;
+        splitMediaToMuxerParameters();
+    }
+
+    ~MuxerNativeTestHelper() {
+        for (auto format : mFormat) AMediaFormat_delete(format);
+        delete[] mBuffer;
+        for (const auto& buffInfoTrack : mBufferInfo) {
+            for (auto info : buffInfoTrack) delete info;
+        }
+    }
+
+    int getTrackCount() { return mTrackCount; }
+
+    bool registerTrack(AMediaMuxer* muxer);
+
+    bool insertSampleData(AMediaMuxer* muxer);
+
+    bool muxMedia(AMediaMuxer* muxer);
+
+    bool combineMedias(AMediaMuxer* muxer, MuxerNativeTestHelper* that, const int* repeater);
+
+    bool equals(MuxerNativeTestHelper* that);
+
+    void offsetTimeStamp(int trackID, long tsOffset, int sampleOffset);
+
+  private:
+    void splitMediaToMuxerParameters();
+
+    static const int STTS_TOLERANCE = 100;
+    const char* mSrcPath;
+    const char* mMime;
+    int mTrackCount;
+    std::vector<AMediaFormat*> mFormat;
+    uint8_t* mBuffer;
+    std::vector<std::vector<AMediaCodecBufferInfo*>> mBufferInfo;
+    std::map<int, int> mInpIndexMap;
+    std::vector<int> mTrackIdxOrder;
+    int mFrameLimit;
+    // combineMedias() uses local version of this variable
+    std::map<int, int> mOutIndexMap;
+};
+
+void MuxerNativeTestHelper::splitMediaToMuxerParameters() {
+    FILE* ifp = fopen(mSrcPath, "rbe");
+    int fd;
+    int fileSize;
+    if (ifp) {
+        struct stat buf {};
+        stat(mSrcPath, &buf);
+        fileSize = buf.st_size;
+        fd = fileno(ifp);
+    } else {
+        return;
+    }
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    if (extractor == nullptr) {
+        fclose(ifp);
+        return;
+    }
+    // Set up MediaExtractor to read from the source.
+    media_status_t status = AMediaExtractor_setDataSourceFd(extractor, fd, 0, fileSize);
+    if (AMEDIA_OK != status) {
+        AMediaExtractor_delete(extractor);
+        fclose(ifp);
+        return;
+    }
+
+    // Set up MediaFormat
+    int index = 0;
+    for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(extractor); trackID++) {
+        AMediaExtractor_selectTrack(extractor, trackID);
+        AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackID);
+        if (mMime == nullptr) {
+            mTrackCount++;
+            mFormat.push_back(format);
+            mInpIndexMap[trackID] = index++;
+        } else {
+            const char* mime;
+            bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+            if (hasKey && !strcmp(mime, mMime)) {
+                mTrackCount++;
+                mFormat.push_back(format);
+                mInpIndexMap[trackID] = index;
+                break;
+            } else {
+                AMediaFormat_delete(format);
+                AMediaExtractor_unselectTrack(extractor, trackID);
+            }
+        }
+    }
+
+    if (mTrackCount <= 0) {
+        AMediaExtractor_delete(extractor);
+        fclose(ifp);
+        return;
+    }
+
+    // Set up location for elementary stream
+    int bufferSize = ((fileSize + 127) >> 7) << 7;
+    // Ideally, Sum of return values of extractor.readSampleData(...) should not exceed
+    // source file size. But in case of Vorbis, aosp extractor appends an additional 4 bytes to
+    // the data at every readSampleData() call. bufferSize <<= 1 empirically large enough to
+    // hold the excess 4 bytes per read call
+    bufferSize <<= 1;
+    mBuffer = new uint8_t[bufferSize];
+    if (mBuffer == nullptr) {
+        mTrackCount = 0;
+        AMediaExtractor_delete(extractor);
+        fclose(ifp);
+        return;
+    }
+
+    // Let MediaExtractor do its thing
+    bool sawEOS = false;
+    int frameCount = 0;
+    int offset = 0;
+    mBufferInfo.resize(mTrackCount);
+    while (!sawEOS && frameCount < mFrameLimit) {
+        auto* bufferInfo = new AMediaCodecBufferInfo();
+        bufferInfo->offset = offset;
+        bufferInfo->size =
+                AMediaExtractor_readSampleData(extractor, mBuffer + offset, (bufferSize - offset));
+        if (bufferInfo->size < 0) {
+            sawEOS = true;
+        } else {
+            bufferInfo->presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
+            bufferInfo->flags = AMediaExtractor_getSampleFlags(extractor);
+            int trackID = AMediaExtractor_getSampleTrackIndex(extractor);
+            mTrackIdxOrder.push_back(trackID);
+            mBufferInfo[(mInpIndexMap.at(trackID))].push_back(bufferInfo);
+            AMediaExtractor_advance(extractor);
+            frameCount++;
+        }
+        offset += bufferInfo->size;
+    }
+
+    AMediaExtractor_delete(extractor);
+    fclose(ifp);
+}
+
+bool MuxerNativeTestHelper::registerTrack(AMediaMuxer* muxer) {
+    for (int trackID = 0; trackID < mTrackCount; trackID++) {
+        int dstIndex = AMediaMuxer_addTrack(muxer, mFormat[trackID]);
+        if (dstIndex < 0) return false;
+        mOutIndexMap[trackID] = dstIndex;
+    }
+    return true;
+}
+
+bool MuxerNativeTestHelper::insertSampleData(AMediaMuxer* muxer) {
+    // write all registered tracks in interleaved order
+    int* frameCount = new int[mTrackCount]{0};
+    for (int trackID : mTrackIdxOrder) {
+        int index = mInpIndexMap.at(trackID);
+        AMediaCodecBufferInfo* info = mBufferInfo[index][frameCount[index]];
+        if (AMediaMuxer_writeSampleData(muxer, mOutIndexMap.at(index), mBuffer, info) !=
+            AMEDIA_OK) {
+            delete[] frameCount;
+            return false;
+        }
+        ALOGV("Track: %d Timestamp: %d", trackID, (int)info->presentationTimeUs);
+        frameCount[index]++;
+    }
+    delete[] frameCount;
+    ALOGV("Total track samples %d", (int)mTrackIdxOrder.size());
+    return true;
+}
+
+bool MuxerNativeTestHelper::muxMedia(AMediaMuxer* muxer) {
+    return (registerTrack(muxer) && (AMediaMuxer_start(muxer) == AMEDIA_OK) &&
+            insertSampleData(muxer) && (AMediaMuxer_stop(muxer) == AMEDIA_OK));
+}
+
+bool MuxerNativeTestHelper::combineMedias(AMediaMuxer* muxer, MuxerNativeTestHelper* that,
+                                          const int* repeater) {
+    if (that == nullptr) return false;
+    if (repeater == nullptr) return false;
+
+    // register tracks
+    int totalTracksToAdd = repeater[0] * this->mTrackCount + repeater[1] * that->mTrackCount;
+    int outIndexMap[totalTracksToAdd];
+    MuxerNativeTestHelper* group[2]{this, that};
+    for (int k = 0, idx = 0; k < 2; k++) {
+        for (int j = 0; j < repeater[k]; j++) {
+            for (AMediaFormat* format : group[k]->mFormat) {
+                int dstIndex = AMediaMuxer_addTrack(muxer, format);
+                if (dstIndex < 0) return false;
+                outIndexMap[idx++] = dstIndex;
+            }
+        }
+    }
+    // start
+    if (AMediaMuxer_start(muxer) != AMEDIA_OK) return false;
+    // write sample data
+    // write all registered tracks in planar order viz all samples of a track A then all
+    // samples of track B, ...
+    for (int k = 0, idx = 0; k < 2; k++) {
+        for (int j = 0; j < repeater[k]; j++) {
+            for (int i = 0; i < group[k]->mTrackCount; i++) {
+                for (int p = 0; p < group[k]->mBufferInfo[i].size(); p++) {
+                    AMediaCodecBufferInfo* info = group[k]->mBufferInfo[i][p];
+                    if (AMediaMuxer_writeSampleData(muxer, outIndexMap[idx], group[k]->mBuffer,
+                                                    info) != AMEDIA_OK) {
+                        return false;
+                    }
+                    ALOGV("Track: %d Timestamp: %d", outIndexMap[idx],
+                          (int)info->presentationTimeUs);
+                }
+                idx++;
+            }
+        }
+    }
+    // stop
+    return (AMediaMuxer_stop(muxer) == AMEDIA_OK);
+}
+
+// returns true if 'this' stream is a subset of 'o'. That is all tracks in current media
+// stream are present in ref media stream
+bool MuxerNativeTestHelper::equals(MuxerNativeTestHelper* that) {
+    if (this == that) return true;
+    if (that == nullptr) return false;
+
+    for (int i = 0; i < mTrackCount; i++) {
+        AMediaFormat* thisFormat = mFormat[i];
+        const char* thisMime = nullptr;
+        AMediaFormat_getString(thisFormat, AMEDIAFORMAT_KEY_MIME, &thisMime);
+        int j = 0;
+        for (; j < that->mTrackCount; j++) {
+            AMediaFormat* thatFormat = that->mFormat[j];
+            const char* thatMime = nullptr;
+            AMediaFormat_getString(thatFormat, AMEDIAFORMAT_KEY_MIME, &thatMime);
+            if (thisMime != nullptr && thatMime != nullptr && !strcmp(thisMime, thatMime)) {
+                if (mBufferInfo[i].size() == that->mBufferInfo[j].size()) {
+                    int flagsDiff = 0, sizeDiff = 0, tsDiff = 0;
+                    for (int k = 0; k < mBufferInfo[i].size(); k++) {
+                        AMediaCodecBufferInfo* thisInfo = mBufferInfo[i][k];
+                        AMediaCodecBufferInfo* thatInfo = that->mBufferInfo[j][k];
+                        if (thisInfo->flags != thatInfo->flags) {
+                            flagsDiff++;
+                        }
+                        if (thisInfo->size != thatInfo->size) {
+                            sizeDiff++;
+                        }
+                        if (abs(thisInfo->presentationTimeUs - thatInfo->presentationTimeUs) >
+                            STTS_TOLERANCE) {
+                            tsDiff++;
+                        }
+                    }
+                    if (flagsDiff == 0 && sizeDiff == 0 && tsDiff == 0)
+                        break;
+                    else {
+                        ALOGV("For mime %s, Total Samples %d, flagsDiff %d, sizeDiff %d, tsDiff %d",
+                              thisMime, (int)mBufferInfo[i].size(), flagsDiff, sizeDiff, tsDiff);
+                    }
+                }
+            }
+        }
+        if (j == that->mTrackCount) {
+            ALOGV("For mime %s, Couldn't find a match", thisMime);
+            return false;
+        }
+    }
+    return true;
+}
+
+void MuxerNativeTestHelper::offsetTimeStamp(int trackID, long tsOffset, int sampleOffset) {
+    // offset pts of samples from index sampleOffset till the end by tsOffset
+    if (trackID < mTrackCount) {
+        for (int i = sampleOffset; i < mBufferInfo[trackID].size(); i++) {
+            AMediaCodecBufferInfo* info = mBufferInfo[trackID][i];
+            info->presentationTimeUs += tsOffset;
+        }
+    }
+}
+
+static bool isCodecContainerPairValid(MuxerFormat format, const char* mime) {
+    static const std::map<MuxerFormat, std::vector<const char*>> codecListforType = {
+            {OUTPUT_FORMAT_MPEG_4,
+             {AMEDIA_MIMETYPE_VIDEO_MPEG4, AMEDIA_MIMETYPE_VIDEO_H263, AMEDIA_MIMETYPE_VIDEO_AVC,
+              AMEDIA_MIMETYPE_VIDEO_HEVC, AMEDIA_MIMETYPE_AUDIO_AAC}},
+            {OUTPUT_FORMAT_WEBM,
+             {AMEDIA_MIMETYPE_VIDEO_VP8, AMEDIA_MIMETYPE_VIDEO_VP9, AMEDIA_MIMETYPE_AUDIO_VORBIS,
+              AMEDIA_MIMETYPE_AUDIO_OPUS}},
+            {OUTPUT_FORMAT_THREE_GPP,
+             {AMEDIA_MIMETYPE_VIDEO_MPEG4, AMEDIA_MIMETYPE_VIDEO_H263, AMEDIA_MIMETYPE_VIDEO_AVC,
+              AMEDIA_MIMETYPE_AUDIO_AAC, AMEDIA_MIMETYPE_AUDIO_AMR_NB,
+              AMEDIA_MIMETYPE_AUDIO_AMR_WB}},
+            {OUTPUT_FORMAT_OGG, {AMEDIA_MIMETYPE_AUDIO_OPUS}},
+    };
+
+    if (format == OUTPUT_FORMAT_MPEG_4 &&
+        strncmp(mime, "application/", strlen("application/")) == 0)
+        return true;
+
+    auto it = codecListforType.find(format);
+    if (it != codecListforType.end())
+        for (auto it2 : it->second)
+            if (strcmp(it2, mime) == 0) return true;
+
+    return false;
+}
+
+static jboolean nativeTestSetLocation(JNIEnv* env, jobject, jint jformat, jstring jsrcPath,
+                                      jstring jdstPath) {
+    bool isPass = true;
+    bool isGeoDataSupported;
+    const float atlanticLat = 14.59f;
+    const float atlanticLong = 28.67f;
+    const float tooFarNorth = 90.5f;
+    const float tooFarWest = -180.5f;
+    const float tooFarSouth = -90.5f;
+    const float tooFarEast = 180.5f;
+    const float annapurnaLat = 28.59f;
+    const float annapurnaLong = 83.82f;
+    const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
+    FILE* ofp = fopen(cdstPath, "wbe+");
+    if (ofp) {
+        AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)jformat);
+        media_status_t status = AMediaMuxer_setLocation(muxer, tooFarNorth, atlanticLong);
+        if (status == AMEDIA_OK) {
+            isPass = false;
+            ALOGE("setLocation succeeds on bad args: (%f, %f)", tooFarNorth, atlanticLong);
+        }
+        status = AMediaMuxer_setLocation(muxer, tooFarSouth, atlanticLong);
+        if (status == AMEDIA_OK) {
+            isPass = false;
+            ALOGE("setLocation succeeds on bad args: (%f, %f)", tooFarSouth, atlanticLong);
+        }
+        status = AMediaMuxer_setLocation(muxer, atlanticLat, tooFarWest);
+        if (status == AMEDIA_OK) {
+            isPass = false;
+            ALOGE("setLocation succeeds on bad args: (%f, %f)", atlanticLat, tooFarWest);
+        }
+        status = AMediaMuxer_setLocation(muxer, atlanticLat, tooFarEast);
+        if (status == AMEDIA_OK) {
+            isPass = false;
+            ALOGE("setLocation succeeds on bad args: (%f, %f)", atlanticLat, tooFarEast);
+        }
+        status = AMediaMuxer_setLocation(muxer, tooFarNorth, tooFarWest);
+        if (status == AMEDIA_OK) {
+            isPass = false;
+            ALOGE("setLocation succeeds on bad args: (%f, %f)", tooFarNorth, tooFarWest);
+        }
+        status = AMediaMuxer_setLocation(muxer, atlanticLat, atlanticLong);
+        isGeoDataSupported = (status == AMEDIA_OK);
+        if (isGeoDataSupported) {
+            status = AMediaMuxer_setLocation(muxer, annapurnaLat, annapurnaLong);
+            if (status != AMEDIA_OK) {
+                isPass = false;
+                ALOGE("setLocation fails on args: (%f, %f)", annapurnaLat, annapurnaLong);
+            }
+        } else {
+            isPass &= ((MuxerFormat)jformat != OUTPUT_FORMAT_MPEG_4 &&
+                       (MuxerFormat)jformat != OUTPUT_FORMAT_THREE_GPP);
+        }
+        const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+        auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
+        if (mediaInfo->registerTrack(muxer) && AMediaMuxer_start(muxer) == AMEDIA_OK) {
+            status = AMediaMuxer_setLocation(muxer, atlanticLat, atlanticLong);
+            if (status == AMEDIA_OK) {
+                isPass = false;
+                ALOGE("setLocation succeeds after starting the muxer");
+            }
+            if (mediaInfo->insertSampleData(muxer) && AMediaMuxer_stop(muxer) == AMEDIA_OK) {
+                status = AMediaMuxer_setLocation(muxer, atlanticLat, atlanticLong);
+                if (status == AMEDIA_OK) {
+                    isPass = false;
+                    ALOGE("setLocation succeeds after stopping the muxer");
+                }
+            } else {
+                isPass = false;
+                ALOGE("failed to writeSampleData or stop muxer");
+            }
+        } else {
+            isPass = false;
+            ALOGE("failed to addTrack or start muxer");
+        }
+        delete mediaInfo;
+        env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+        AMediaMuxer_delete(muxer);
+        fclose(ofp);
+    } else {
+        isPass = false;
+        ALOGE("failed to open output file %s", cdstPath);
+    }
+    env->ReleaseStringUTFChars(jdstPath, cdstPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSetOrientationHint(JNIEnv* env, jobject, jint jformat, jstring jsrcPath,
+                                             jstring jdstPath) {
+    bool isPass = true;
+    bool isOrientationSupported;
+    const int badRotation[] = {360, 45, -90};
+    const int oldRotation = 90;
+    const int currRotation = 180;
+    const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
+    FILE* ofp = fopen(cdstPath, "wbe+");
+    if (ofp) {
+        AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)jformat);
+        media_status_t status;
+        for (int degrees : badRotation) {
+            status = AMediaMuxer_setOrientationHint(muxer, degrees);
+            if (status == AMEDIA_OK) {
+                isPass = false;
+                ALOGE("setOrientationHint succeeds on bad args: %d", degrees);
+            }
+        }
+        status = AMediaMuxer_setOrientationHint(muxer, oldRotation);
+        isOrientationSupported = (status == AMEDIA_OK);
+        if (isOrientationSupported) {
+            status = AMediaMuxer_setOrientationHint(muxer, currRotation);
+            if (status != AMEDIA_OK) {
+                isPass = false;
+                ALOGE("setOrientationHint fails on args: %d", currRotation);
+            }
+        } else {
+            isPass &= ((MuxerFormat)jformat != OUTPUT_FORMAT_MPEG_4 &&
+                       (MuxerFormat)jformat != OUTPUT_FORMAT_THREE_GPP);
+        }
+        const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+        auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
+        if (mediaInfo->registerTrack(muxer) && AMediaMuxer_start(muxer) == AMEDIA_OK) {
+            status = AMediaMuxer_setOrientationHint(muxer, currRotation);
+            if (status == AMEDIA_OK) {
+                isPass = false;
+                ALOGE("setOrientationHint succeeds after starting the muxer");
+            }
+            if (mediaInfo->insertSampleData(muxer) && AMediaMuxer_stop(muxer) == AMEDIA_OK) {
+                status = AMediaMuxer_setOrientationHint(muxer, currRotation);
+                if (status == AMEDIA_OK) {
+                    isPass = false;
+                    ALOGE("setOrientationHint succeeds after stopping the muxer");
+                }
+            } else {
+                isPass = false;
+                ALOGE("failed to writeSampleData or stop muxer");
+            }
+        } else {
+            isPass = false;
+            ALOGE("failed to addTrack or start muxer");
+        }
+        delete mediaInfo;
+        env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+        AMediaMuxer_delete(muxer);
+        fclose(ofp);
+    } else {
+        isPass = false;
+        ALOGE("failed to open output file %s", cdstPath);
+    }
+    env->ReleaseStringUTFChars(jdstPath, cdstPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestMultiTrack(JNIEnv* env, jobject, jint jformat, jstring jsrcPathA,
+                                     jstring jsrcPathB, jstring jrefPath, jstring jdstPath) {
+    bool isPass = true;
+    const char* csrcPathA = env->GetStringUTFChars(jsrcPathA, nullptr);
+    const char* csrcPathB = env->GetStringUTFChars(jsrcPathB, nullptr);
+    auto* mediaInfoA = new MuxerNativeTestHelper(csrcPathA);
+    auto* mediaInfoB = new MuxerNativeTestHelper(csrcPathB);
+    if (mediaInfoA->getTrackCount() == 1 && mediaInfoB->getTrackCount() == 1) {
+        const char* crefPath = env->GetStringUTFChars(jrefPath, nullptr);
+        // number of times to repeat {mSrcFileA, mSrcFileB} in Output
+        int numTracks[][2]{{1, 1}, {2, 0}, {0, 2}, {1, 2}, {2, 1}};
+        // prepare reference
+        FILE* rfp = fopen(crefPath, "wbe+");
+        if (rfp) {
+            AMediaMuxer* muxer = AMediaMuxer_new(fileno(rfp), (OutputFormat)jformat);
+            bool muxStatus = mediaInfoA->combineMedias(muxer, mediaInfoB, numTracks[0]);
+            AMediaMuxer_delete(muxer);
+            fclose(rfp);
+            if (muxStatus) {
+                auto* refInfo = new MuxerNativeTestHelper(crefPath);
+                if (!mediaInfoA->equals(refInfo) || !mediaInfoB->equals(refInfo)) {
+                    isPass = false;
+                    ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing src A and src B "
+                          "failed", csrcPathA, csrcPathB, jformat);
+                } else {
+                    const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
+                    for (int i = 1; i < sizeof(numTracks) / sizeof(numTracks[0]) && isPass; i++) {
+                        FILE* ofp = fopen(cdstPath, "wbe+");
+                        if (ofp) {
+                            muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)jformat);
+                            bool status =
+                                    mediaInfoA->combineMedias(muxer, mediaInfoB, numTracks[i]);
+                            AMediaMuxer_delete(muxer);
+                            fclose(ofp);
+                            if (status) {
+                                auto* dstInfo = new MuxerNativeTestHelper(cdstPath);
+                                if (!dstInfo->equals(refInfo)) {
+                                    isPass = false;
+                                    ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing "
+                                          "src A: %d, src B: %d failed", csrcPathA, csrcPathB,
+                                          jformat, numTracks[i][0], numTracks[i][1]);
+                                }
+                                delete dstInfo;
+                            } else {
+                                if ((MuxerFormat)jformat != OUTPUT_FORMAT_MPEG_4) {
+                                    isPass = false;
+                                    ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing "
+                                          "src A: %d, src B: %d failed", csrcPathA, csrcPathB,
+                                          jformat, numTracks[i][0], numTracks[i][1]);
+                                }
+                            }
+                        } else {
+                            isPass = false;
+                            ALOGE("failed to open output file %s", cdstPath);
+                        }
+                    }
+                    env->ReleaseStringUTFChars(jdstPath, cdstPath);
+                }
+                delete refInfo;
+            } else {
+                if ((MuxerFormat)jformat != OUTPUT_FORMAT_OGG) {
+                    isPass = false;
+                    ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing src A and src B "
+                          "failed", csrcPathA, csrcPathB, jformat);
+                }
+            }
+        } else {
+            isPass = false;
+            ALOGE("failed to open reference output file %s", crefPath);
+        }
+        env->ReleaseStringUTFChars(jrefPath, crefPath);
+    } else {
+        isPass = false;
+        if (mediaInfoA->getTrackCount() != 1) {
+            ALOGE("error: file %s, track count exp/rec - %d/%d", csrcPathA, 1,
+                  mediaInfoA->getTrackCount());
+        }
+        if (mediaInfoB->getTrackCount() != 1) {
+            ALOGE("error: file %s, track count exp/rec - %d/%d", csrcPathB, 1,
+                  mediaInfoB->getTrackCount());
+        }
+    }
+    env->ReleaseStringUTFChars(jsrcPathA, csrcPathA);
+    env->ReleaseStringUTFChars(jsrcPathB, csrcPathB);
+    delete mediaInfoA;
+    delete mediaInfoB;
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestOffsetPts(JNIEnv* env, jobject, jint format, jstring jsrcPath,
+                                    jstring jdstPath, jintArray joffsetIndices) {
+    bool isPass = true;
+    const int OFFSET_TS = 111000;
+    jsize len = env->GetArrayLength(joffsetIndices);
+    jint* coffsetIndices = env->GetIntArrayElements(joffsetIndices, nullptr);
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
+    auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
+    if (mediaInfo->getTrackCount() != 0) {
+        for (int trackID = 0; trackID < mediaInfo->getTrackCount() && isPass; trackID++) {
+            for (int i = 0; i < len; i++) {
+                mediaInfo->offsetTimeStamp(trackID, OFFSET_TS, coffsetIndices[i]);
+            }
+            FILE* ofp = fopen(cdstPath, "wbe+");
+            if (ofp) {
+                AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)format);
+                mediaInfo->muxMedia(muxer);
+                AMediaMuxer_delete(muxer);
+                fclose(ofp);
+                auto* outInfo = new MuxerNativeTestHelper(cdstPath);
+                isPass = mediaInfo->equals(outInfo);
+                if (!isPass) {
+                    ALOGE("Validation failed after adding timestamp offset to track %d", trackID);
+                }
+                delete outInfo;
+            } else {
+                isPass = false;
+                ALOGE("failed to open output file %s", cdstPath);
+            }
+            for (int i = len - 1; i >= 0; i--) {
+                mediaInfo->offsetTimeStamp(trackID, -OFFSET_TS, coffsetIndices[i]);
+            }
+        }
+    } else {
+        isPass = false;
+        ALOGE("no valid track found in input file %s", csrcPath);
+    }
+    env->ReleaseStringUTFChars(jdstPath, cdstPath);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    env->ReleaseIntArrayElements(joffsetIndices, coffsetIndices, 0);
+    delete mediaInfo;
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSimpleMux(JNIEnv* env, jobject, jstring jsrcPath, jstring jdstPath,
+                                    jstring jmime, jstring jselector) {
+    bool isPass = true;
+    const char* cmime = env->GetStringUTFChars(jmime, nullptr);
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    const char* cselector = env->GetStringUTFChars(jselector, nullptr);
+    auto* mediaInfo = new MuxerNativeTestHelper(csrcPath, cmime);
+    static const std::map<MuxerFormat, const char*> formatStringPair = {
+            {OUTPUT_FORMAT_MPEG_4, "mp4"},
+            {OUTPUT_FORMAT_WEBM, "webm"},
+            {OUTPUT_FORMAT_THREE_GPP, "3gp"},
+            {OUTPUT_FORMAT_HEIF, "heif"},
+            {OUTPUT_FORMAT_OGG, "ogg"}};
+    if (mediaInfo->getTrackCount() == 1) {
+        const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
+        for (int fmt = OUTPUT_FORMAT_START; fmt <= OUTPUT_FORMAT_LIST_END && isPass; fmt++) {
+            auto it = formatStringPair.find((MuxerFormat)fmt);
+            if (it == formatStringPair.end() || strstr(cselector, it->second) == nullptr) {
+                continue;
+            }
+            if (fmt == OUTPUT_FORMAT_WEBM) continue;  // TODO(b/146923551)
+            FILE* ofp = fopen(cdstPath, "wbe+");
+            if (ofp) {
+                AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)fmt);
+                bool muxStatus = mediaInfo->muxMedia(muxer);
+                bool result = true;
+                AMediaMuxer_delete(muxer);
+                fclose(ofp);
+                if (muxStatus) {
+                    auto* outInfo = new MuxerNativeTestHelper(cdstPath, cmime);
+                    result = mediaInfo->equals(outInfo);
+                    delete outInfo;
+                }
+                if ((muxStatus && !result) ||
+                    (!muxStatus && isCodecContainerPairValid((MuxerFormat)fmt, cmime))) {
+                    isPass = false;
+                    ALOGE("error: file %s, mime %s, output != clone(input) for format %d", csrcPath,
+                          cmime, fmt);
+                }
+            } else {
+                isPass = false;
+                ALOGE("error: file %s, mime %s, failed to open output file %s", csrcPath, cmime,
+                      cdstPath);
+            }
+        }
+        env->ReleaseStringUTFChars(jdstPath, cdstPath);
+    } else {
+        isPass = false;
+        ALOGE("error: file %s, mime %s, track count exp/rec - %d/%d", csrcPath, cmime, 1,
+              mediaInfo->getTrackCount());
+    }
+    env->ReleaseStringUTFChars(jselector, cselector);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    env->ReleaseStringUTFChars(jmime, cmime);
+    delete mediaInfo;
+    return static_cast<jboolean>(isPass);
+}
+
+int registerAndroidMediaV2CtsMuxerTestApi(JNIEnv* env) {
+    const JNINativeMethod methodTable[] = {
+            {"nativeTestSetOrientationHint", "(ILjava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestSetOrientationHint},
+            {"nativeTestSetLocation", "(ILjava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestSetLocation},
+    };
+    jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestApi");
+    return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
+}
+
+int registerAndroidMediaV2CtsMuxerTestMultiTrack(JNIEnv* env) {
+    const JNINativeMethod methodTable[] = {
+            {"nativeTestMultiTrack",
+             "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestMultiTrack},
+    };
+    jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestMultiTrack");
+    return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
+}
+
+int registerAndroidMediaV2CtsMuxerTestOffsetPts(JNIEnv* env) {
+    const JNINativeMethod methodTable[] = {
+            {"nativeTestOffsetPts", "(ILjava/lang/String;Ljava/lang/String;[I)Z",
+             (void*)nativeTestOffsetPts},
+    };
+    jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestOffsetPts");
+    return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
+}
+
+int registerAndroidMediaV2CtsMuxerTestSimpleMux(JNIEnv* env) {
+    const JNINativeMethod methodTable[] = {
+            {"nativeTestSimpleMux",
+             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestSimpleMux},
+    };
+    jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestSimpleMux");
+    return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
+}
+
+extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
+    if (registerAndroidMediaV2CtsMuxerTestApi(env) != JNI_OK) return JNI_ERR;
+    if (registerAndroidMediaV2CtsMuxerTestMultiTrack(env) != JNI_OK) return JNI_ERR;
+    if (registerAndroidMediaV2CtsMuxerTestOffsetPts(env) != JNI_OK) return JNI_ERR;
+    if (registerAndroidMediaV2CtsMuxerTestSimpleMux(env) != JNI_OK) return JNI_ERR;
+    return JNI_VERSION_1_6;
+}
\ No newline at end of file
diff --git a/tests/media/src/android/mediav2/cts/MuxerTest.java b/tests/media/src/android/mediav2/cts/MuxerTest.java
new file mode 100644
index 0000000..b20ee08
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/MuxerTest.java
@@ -0,0 +1,1008 @@
+/*
+ * 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.
+ */
+
+package android.mediav2.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
+import android.media.MediaMuxer;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * MuxerTestHelper breaks a media file to elements that a muxer can use to rebuild its clone.
+ * While testing muxer, if the test doesn't use MediaCodecs class to generate elementary
+ * stream, but uses MediaExtractor, this class will be handy
+ */
+class MuxerTestHelper {
+    private static final String LOG_TAG = MuxerTestHelper.class.getSimpleName();
+    private static final boolean ENABLE_LOGS = false;
+    static final int STTS_TOLERANCE = 100;
+    private String mSrcPath;
+    private String mMime;
+    private int mTrackCount;
+    private ArrayList<MediaFormat> mFormat = new ArrayList<>();
+    private ByteBuffer mBuff;
+    private ArrayList<ArrayList<MediaCodec.BufferInfo>> mBufferInfo;
+    private HashMap<Integer, Integer> mInpIndexMap = new HashMap<>();
+    private ArrayList<Integer> mTrackIdxOrder = new ArrayList<>();
+    private int mFrameLimit;
+    // combineMedias() uses local version of this variable
+    private HashMap<Integer, Integer> mOutIndexMap = new HashMap<>();
+
+    private void splitMediaToMuxerParameters() throws IOException {
+        // Set up MediaExtractor to read from the source.
+        MediaExtractor extractor = new MediaExtractor();
+        extractor.setDataSource(mSrcPath);
+
+        // Set up MediaFormat
+        int index = 0;
+        for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) {
+            extractor.selectTrack(trackID);
+            MediaFormat format = extractor.getTrackFormat(trackID);
+            if (mMime == null) {
+                mTrackCount++;
+                mFormat.add(format);
+                mInpIndexMap.put(trackID, index++);
+            } else {
+                String mime = format.getString(MediaFormat.KEY_MIME);
+                if (mime != null && mime.equals(mMime)) {
+                    mTrackCount++;
+                    mFormat.add(format);
+                    mInpIndexMap.put(trackID, index);
+                    break;
+                } else {
+                    extractor.unselectTrack(trackID);
+                }
+            }
+        }
+
+        if (0 == mTrackCount) {
+            extractor.release();
+            throw new IllegalArgumentException("could not find usable track in file " + mSrcPath);
+        }
+
+        // Set up location for elementary stream
+        File file = new File(mSrcPath);
+        int bufferSize = (int) file.length();
+        bufferSize = ((bufferSize + 127) >> 7) << 7;
+        // Ideally, Sum of return values of extractor.readSampleData(...) should not exceed
+        // source file size. But in case of Vorbis, aosp extractor appends an additional 4 bytes to
+        // the data at every readSampleData() call. bufferSize <<= 1 empirically large enough to
+        // hold the excess 4 bytes per read call
+        bufferSize <<= 1;
+        mBuff = ByteBuffer.allocate(bufferSize);
+
+        // Set up space for bufferInfo of all samples of all tracks
+        mBufferInfo = new ArrayList<>(mTrackCount);
+        for (index = 0; index < mTrackCount; index++) {
+            mBufferInfo.add(new ArrayList<MediaCodec.BufferInfo>());
+        }
+
+        // Let MediaExtractor do its thing
+        boolean sawEOS = false;
+        int frameCount = 0;
+        int offset = 0;
+        while (!sawEOS && frameCount < mFrameLimit) {
+            int trackID;
+            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+            bufferInfo.offset = offset;
+            bufferInfo.size = extractor.readSampleData(mBuff, offset);
+
+            if (bufferInfo.size < 0) {
+                sawEOS = true;
+            } else {
+                bufferInfo.presentationTimeUs = extractor.getSampleTime();
+                bufferInfo.flags = extractor.getSampleFlags();
+                trackID = extractor.getSampleTrackIndex();
+                mTrackIdxOrder.add(trackID);
+                mBufferInfo.get(mInpIndexMap.get(trackID)).add(bufferInfo);
+                extractor.advance();
+                frameCount++;
+            }
+            offset += bufferInfo.size;
+        }
+        extractor.release();
+    }
+
+    void registerTrack(MediaMuxer muxer) {
+        for (int trackID = 0; trackID < mTrackCount; trackID++) {
+            int dstIndex = muxer.addTrack(mFormat.get(trackID));
+            mOutIndexMap.put(trackID, dstIndex);
+        }
+    }
+
+    void insertSampleData(MediaMuxer muxer) {
+        // write all registered tracks in interleaved order
+        int[] frameCount = new int[mTrackCount];
+        for (int i = 0; i < mTrackIdxOrder.size(); i++) {
+            int trackID = mTrackIdxOrder.get(i);
+            int index = mInpIndexMap.get(trackID);
+            MediaCodec.BufferInfo bufferInfo = mBufferInfo.get(index).get(frameCount[index]);
+            muxer.writeSampleData(mOutIndexMap.get(index), mBuff, bufferInfo);
+            frameCount[index]++;
+            if (ENABLE_LOGS) {
+                Log.v(LOG_TAG, "Track: " + index + " Timestamp: " + bufferInfo.presentationTimeUs);
+            }
+        }
+        if (ENABLE_LOGS) {
+            Log.v(LOG_TAG, "Total samples: " + mTrackIdxOrder.size());
+        }
+    }
+
+    void muxMedia(MediaMuxer muxer) {
+        registerTrack(muxer);
+        muxer.start();
+        insertSampleData(muxer);
+        muxer.stop();
+    }
+
+    void combineMedias(MediaMuxer muxer, Object o, int[] repeater) {
+        if (o == null || getClass() != o.getClass())
+            throw new IllegalArgumentException("Invalid Object handle");
+        if (null == repeater || repeater.length < 2)
+            throw new IllegalArgumentException("Invalid Parameter, repeater");
+        MuxerTestHelper that = (MuxerTestHelper) o;
+
+        // add tracks
+        int totalTracksToAdd = repeater[0] * this.mTrackCount + repeater[1] * that.mTrackCount;
+        int[] outIndexMap = new int[totalTracksToAdd];
+        MuxerTestHelper[] group = {this, that};
+        for (int k = 0, idx = 0; k < group.length; k++) {
+            for (int j = 0; j < repeater[k]; j++) {
+                for (MediaFormat format : group[k].mFormat) {
+                    outIndexMap[idx++] = muxer.addTrack(format);
+                }
+            }
+        }
+
+        // mux samples
+        // write all registered tracks in planar order viz all samples of a track A then all
+        // samples of track B, ...
+        muxer.start();
+        for (int k = 0, idx = 0; k < group.length; k++) {
+            for (int j = 0; j < repeater[k]; j++) {
+                for (int i = 0; i < group[k].mTrackCount; i++) {
+                    ArrayList<MediaCodec.BufferInfo> bufInfos = group[k].mBufferInfo.get(i);
+                    for (int p = 0; p < bufInfos.size(); p++) {
+                        MediaCodec.BufferInfo bufInfo = bufInfos.get(p);
+                        muxer.writeSampleData(outIndexMap[idx], group[k].mBuff, bufInfo);
+                        if (ENABLE_LOGS) {
+                            Log.v(LOG_TAG, "Track: " + outIndexMap[idx] + " Timestamp: " +
+                                    bufInfo.presentationTimeUs);
+                        }
+                    }
+                    idx++;
+                }
+            }
+        }
+        muxer.stop();
+    }
+
+    MuxerTestHelper(String srcPath, String mime, int frameLimit) throws IOException {
+        mSrcPath = srcPath;
+        mMime = mime;
+        if (frameLimit < 0) frameLimit = Integer.MAX_VALUE;
+        mFrameLimit = frameLimit;
+        splitMediaToMuxerParameters();
+    }
+
+    MuxerTestHelper(String srcPath, String mime) throws IOException {
+        this(srcPath, mime, -1);
+    }
+
+    MuxerTestHelper(String srcPath, int frameLimit) throws IOException {
+        this(srcPath, null, frameLimit);
+    }
+
+    MuxerTestHelper(String srcPath) throws IOException {
+        this(srcPath, null, -1);
+    }
+
+    int getTrackCount() {
+        return mTrackCount;
+    }
+
+    // offset pts of samples from index sampleOffset till the end by tsOffset
+    void offsetTimeStamp(int trackID, long tsOffset, int sampleOffset) {
+        if (trackID < mTrackCount) {
+            for (int i = sampleOffset; i < mBufferInfo.get(trackID).size(); i++) {
+                MediaCodec.BufferInfo bufferInfo = mBufferInfo.get(trackID).get(i);
+                bufferInfo.presentationTimeUs += tsOffset;
+            }
+        }
+    }
+
+    @Override
+    // returns true if 'this' stream is a subset of 'o'. That is all tracks in current media
+    // stream are present in ref media stream
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        MuxerTestHelper that = (MuxerTestHelper) o;
+
+        for (int i = 0; i < mTrackCount; i++) {
+            MediaFormat thisFormat = mFormat.get(i);
+            String thisMime = thisFormat.getString(MediaFormat.KEY_MIME);
+            int j = 0;
+            for (; j < that.mTrackCount; j++) {
+                MediaFormat thatFormat = that.mFormat.get(j);
+                String thatMime = thatFormat.getString(MediaFormat.KEY_MIME);
+                if (thisMime != null && thisMime.equals(thatMime)) {
+                    if (mBufferInfo.get(i).size() == that.mBufferInfo.get(j).size()) {
+                        int flagsDiff = 0, sizeDiff = 0, tsDiff = 0;
+                        for (int k = 0; k < mBufferInfo.get(i).size(); k++) {
+                            MediaCodec.BufferInfo thisInfo = mBufferInfo.get(i).get(k);
+                            MediaCodec.BufferInfo thatInfo = that.mBufferInfo.get(j).get(k);
+                            if (thisInfo.flags != thatInfo.flags) {
+                                flagsDiff++;
+                            }
+                            if (thisInfo.size != thatInfo.size) {
+                                sizeDiff++;
+                            }
+                            if (Math.abs(
+                                    thisInfo.presentationTimeUs - thatInfo.presentationTimeUs) >
+                                    STTS_TOLERANCE) {
+                                tsDiff++;
+                            }
+                        }
+                        if (flagsDiff != 0 || sizeDiff != 0 || tsDiff != 0) {
+                            if (ENABLE_LOGS) {
+                                Log.d(LOG_TAG, "For track: " + thisMime +
+                                        " Total Samples: " + mBufferInfo.get(i).size() +
+                                        " flagsDiff: " + flagsDiff +
+                                        " sizeDiff: " + sizeDiff +
+                                        " tsDiff: " + tsDiff);
+                            }
+                        } else break;
+                    } else {
+                        if (ENABLE_LOGS) {
+                            Log.d(LOG_TAG, "Mime matched but sample count different." +
+                                    " Total Samples ref/test: " + mBufferInfo.get(i).size() + '/' +
+                                    that.mBufferInfo.get(j).size());
+                        }
+                    }
+                }
+            }
+            if (j == that.mTrackCount) {
+                if (ENABLE_LOGS) {
+                    Log.d(LOG_TAG, "For track: " + thisMime + " Couldn't find a match ");
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+}
+
+@RunWith(Enclosed.class)
+public class MuxerTest {
+    // duplicate definitions of hide fields of MediaMuxer.OutputFormat.
+    private static final int MUXER_OUTPUT_FIRST = 0;
+    private static final int MUXER_OUTPUT_LAST = MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG;
+
+    private static final String MUX_SEL_KEY = "mux-sel";
+    private static String selector;
+    private static boolean[] muxSelector = new boolean[MUXER_OUTPUT_LAST + 1];
+    private static HashMap<Integer, String> formatStringPair = new HashMap<>();
+
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        final String defSel = "mp4;webm;3gp;ogg";
+        selector = (null == args.getString(MUX_SEL_KEY)) ? defSel : args.getString(MUX_SEL_KEY);
+
+        createFormatStringPair();
+        for (int format = MUXER_OUTPUT_FIRST; format <= MUXER_OUTPUT_LAST; format++) {
+            muxSelector[format] = selector.contains(formatStringPair.get(format));
+        }
+    }
+
+    static private void createFormatStringPair() {
+        formatStringPair.put(MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, "mp4");
+        formatStringPair.put(MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM, "webm");
+        formatStringPair.put(MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP, "3gp");
+        formatStringPair.put(MediaMuxer.OutputFormat.MUXER_OUTPUT_HEIF, "heif");
+        formatStringPair.put(MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG, "ogg");
+    }
+
+    static private boolean shouldRunTest(int format) {
+        return muxSelector[format];
+    }
+
+    /**
+     * Tests MediaMuxer API that are dependent on MediaMuxer.OutputFormat. setLocation,
+     * setOrientationHint are dependent on the mime type and OutputFormat. Legality of these APIs
+     * are tested in this class.
+     */
+    @SmallTest
+    @RunWith(Parameterized.class)
+    public static class TestApi {
+        private int mOutFormat;
+        private String mSrcFile;
+        private String mInpPath;
+        private String mOutPath;
+        private static final float annapurnaLat = 28.59f;
+        private static final float annapurnaLong = 83.82f;
+        private static final float TOLERANCE = 0.0002f;
+        private static final int currRotation = 180;
+
+        static {
+            System.loadLibrary("ctsmediav2muxer_jni");
+        }
+
+        @Before
+        public void prologue() throws IOException {
+            mInpPath = WorkDir.getMediaDirString() + mSrcFile;
+            mOutPath = File.createTempFile("tmp", ".out").getAbsolutePath();
+        }
+
+        @After
+        public void epilogue() {
+            new File(mOutPath).delete();
+        }
+
+        @Parameterized.Parameters
+        public static Collection<Object[]> input() {
+            return Arrays.asList(new Object[][]{
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, "bbb_cif_768kbps_30fps_avc.mp4"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM, "bbb_cif_768kbps_30fps_vp9.mkv"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP, "bbb_cif_768kbps_30fps_h263.mp4"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG, "bbb_stereo_48kHz_192kbps_opus.ogg"},
+            });
+        }
+
+        public TestApi(int outFormat, String srcFile) {
+            mOutFormat = outFormat;
+            mSrcFile = srcFile;
+        }
+
+        private native boolean nativeTestSetLocation(int format, String srcPath, String outPath);
+
+        private native boolean nativeTestSetOrientationHint(int format, String srcPath,
+                String outPath);
+
+        private void verifyLocationInFile(String fileName) {
+            if (mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4 &&
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP) return;
+            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+            retriever.setDataSource(fileName);
+
+            // parsing String location and recover the location information in floats
+            // Make sure the tolerance is very small - due to rounding errors.
+
+            // Get the position of the -/+ sign in location String, which indicates
+            // the beginning of the longitude.
+            String loc = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION);
+            assertTrue(loc != null);
+            int minusIndex = loc.lastIndexOf('-');
+            int plusIndex = loc.lastIndexOf('+');
+
+            assertTrue("+ or - is not found or found only at the beginning [" + loc + "]",
+                    (minusIndex > 0 || plusIndex > 0));
+            int index = Math.max(minusIndex, plusIndex);
+
+            float latitude = Float.parseFloat(loc.substring(0, index - 1));
+            int lastIndex = loc.lastIndexOf('/', index);
+            if (lastIndex == -1) {
+                lastIndex = loc.length();
+            }
+            float longitude = Float.parseFloat(loc.substring(index, lastIndex - 1));
+            assertTrue("Incorrect latitude: " + latitude + " [" + loc + "]",
+                    Math.abs(latitude - annapurnaLat) <= TOLERANCE);
+            assertTrue("Incorrect longitude: " + longitude + " [" + loc + "]",
+                    Math.abs(longitude - annapurnaLong) <= TOLERANCE);
+            retriever.release();
+        }
+
+        private void verifyOrientation(String fileName) {
+            if (mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4 &&
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP) return;
+            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+            retriever.setDataSource(fileName);
+
+            String testDegrees = retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
+            assertTrue(testDegrees != null);
+            assertEquals("Different degrees " + currRotation + " and " + testDegrees,
+                    currRotation, Integer.parseInt(testDegrees));
+            retriever.release();
+        }
+
+        @Test
+        public void testSetLocation() throws IOException {
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            MediaMuxer muxer = new MediaMuxer(mOutPath, mOutFormat);
+            try {
+                boolean isGeoDataSupported = false;
+                final float tooFarNorth = 90.5f;
+                final float tooFarWest = -180.5f;
+                final float tooFarSouth = -90.5f;
+                final float tooFarEast = 180.5f;
+                final float atlanticLat = 14.59f;
+                final float atlanticLong = 28.67f;
+
+                try {
+                    muxer.setLocation(tooFarNorth, atlanticLong);
+                    fail("setLocation succeeded with bad argument: [" + tooFarNorth + "," +
+                            atlanticLong + "]");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    muxer.setLocation(tooFarSouth, atlanticLong);
+                    fail("setLocation succeeded with bad argument: [" + tooFarSouth + "," +
+                            atlanticLong + "]");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    muxer.setLocation(atlanticLat, tooFarWest);
+                    fail("setLocation succeeded with bad argument: [" + atlanticLat + "," +
+                            tooFarWest + "]");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    muxer.setLocation(atlanticLat, tooFarEast);
+                    fail("setLocation succeeded with bad argument: [" + atlanticLat + "," +
+                            tooFarEast + "]");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    muxer.setLocation(tooFarNorth, tooFarWest);
+                    fail("setLocation succeeded with bad argument: [" + tooFarNorth + "," +
+                            tooFarWest + "]");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    muxer.setLocation(atlanticLat, atlanticLong);
+                    isGeoDataSupported = true;
+                } catch (Exception e) {
+                    // can happen
+                }
+
+                if (isGeoDataSupported) {
+                    try {
+                        muxer.setLocation(annapurnaLat, annapurnaLong);
+                    } catch (IllegalArgumentException e) {
+                        fail(e.getMessage());
+                    }
+                } else {
+                    assertTrue(mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4 &&
+                            mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
+                }
+
+                MuxerTestHelper mediaInfo = new MuxerTestHelper(mInpPath, 60);
+                mediaInfo.registerTrack(muxer);
+                muxer.start();
+                // after start
+                try {
+                    muxer.setLocation(0.0f, 0.0f);
+                    fail("SetLocation succeeded after muxer.start()");
+                } catch (IllegalStateException e) {
+                    // Exception
+                }
+                mediaInfo.insertSampleData(muxer);
+                muxer.stop();
+                // after stop
+                try {
+                    muxer.setLocation(annapurnaLat, annapurnaLong);
+                    fail("setLocation() succeeded after muxer.stop()");
+                } catch (IllegalStateException e) {
+                    // expected
+                }
+                muxer.release();
+                // after release
+                try {
+                    muxer.setLocation(annapurnaLat, annapurnaLong);
+                    fail("setLocation() succeeded after muxer.release()");
+                } catch (IllegalStateException e) {
+                    // expected
+                }
+                verifyLocationInFile(mOutPath);
+            } finally {
+                muxer.release();
+            }
+        }
+
+        @Test
+        public void testSetOrientationHint() throws IOException {
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            MediaMuxer muxer = new MediaMuxer(mOutPath, mOutFormat);
+            try {
+                boolean isOrientationSupported = false;
+                final int[] badRotation = {360, 45, -90};
+                final int oldRotation = 90;
+
+                for (int degree : badRotation) {
+                    try {
+                        muxer.setOrientationHint(degree);
+                        fail("setOrientationHint() succeeded with bad argument :" + degree);
+                    } catch (Exception e) {
+                        // expected
+                    }
+                }
+                try {
+                    muxer.setOrientationHint(oldRotation);
+                    isOrientationSupported = true;
+                } catch (Exception e) {
+                    // can happen
+                }
+                if (isOrientationSupported) {
+                    try {
+                        muxer.setOrientationHint(currRotation);
+                    } catch (IllegalArgumentException e) {
+                        fail(e.getMessage());
+                    }
+                } else {
+                    assertTrue(mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4 &&
+                            mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
+                }
+
+                MuxerTestHelper mediaInfo = new MuxerTestHelper(mInpPath, 60);
+                mediaInfo.registerTrack(muxer);
+                muxer.start();
+                // after start
+                try {
+                    muxer.setOrientationHint(0);
+                    fail("setOrientationHint succeeded after muxer.start()");
+                } catch (IllegalStateException e) {
+                    // Exception
+                }
+                mediaInfo.insertSampleData(muxer);
+                muxer.stop();
+                // after stop
+                try {
+                    muxer.setOrientationHint(currRotation);
+                    fail("setOrientationHint() succeeded after muxer.stop()");
+                } catch (IllegalStateException e) {
+                    // expected
+                }
+                muxer.release();
+                // after release
+                try {
+                    muxer.setOrientationHint(currRotation);
+                    fail("setOrientationHint() succeeded after muxer.release()");
+                } catch (IllegalStateException e) {
+                    // expected
+                }
+                verifyOrientation(mOutPath);
+            } finally {
+                muxer.release();
+            }
+        }
+
+        @Test
+        public void testSetLocationNative() {
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            assertTrue(nativeTestSetLocation(mOutFormat, mInpPath, mOutPath));
+            verifyLocationInFile(mOutPath);
+        }
+
+        @Test
+        public void testSetOrientationHintNative() {
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            assertTrue(nativeTestSetOrientationHint(mOutFormat, mInpPath, mOutPath));
+            verifyOrientation(mOutPath);
+        }
+    }
+
+    /**
+     * Tests muxing multiple Video/Audio Tracks
+     */
+    @LargeTest
+    @RunWith(Parameterized.class)
+    public static class TestMultiTrack {
+        private int mOutFormat;
+        private String mSrcFileA;
+        private String mSrcFileB;
+        private String mInpPathA;
+        private String mInpPathB;
+        private String mRefPath;
+        private String mOutPath;
+
+        static {
+            System.loadLibrary("ctsmediav2muxer_jni");
+        }
+
+        @Before
+        public void prologue() throws IOException {
+            mInpPathA = WorkDir.getMediaDirString() + mSrcFileA;
+            mInpPathB = WorkDir.getMediaDirString() + mSrcFileB;
+            mRefPath = File.createTempFile("ref", ".out").getAbsolutePath();
+            mOutPath = File.createTempFile("tmp", ".out").getAbsolutePath();
+        }
+
+        @After
+        public void epilogue() {
+            new File(mRefPath).delete();
+            new File(mOutPath).delete();
+        }
+
+        @Parameterized.Parameters
+        public static Collection<Object[]> input() {
+            return Arrays.asList(new Object[][]{
+                    // audio, video are 3 sec
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, "bbb_cif_768kbps_30fps_mpeg4" +
+                            ".mkv", "bbb_stereo_48kHz_192kbps_aac.mp4"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM, "bbb_cif_768kbps_30fps_vp9.mkv"
+                            , "bbb_stereo_48kHz_192kbps_vorbis.ogg"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP, "bbb_cif_768kbps_30fps_h263.mp4"
+                            , "bbb_mono_16kHz_20kbps_amrwb.amr"},
+
+                    // audio 3 sec, video 10 sec
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, "bbb_qcif_512kbps_30fps_avc" +
+                            ".mp4", "bbb_stereo_48kHz_192kbps_aac.mp4"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM, "bbb_qcif_512kbps_30fps_vp9.webm"
+                            , "bbb_stereo_48kHz_192kbps_vorbis.ogg"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP, "bbb_qcif_512kbps_30fps_h263.3gp"
+                            , "bbb_mono_16kHz_20kbps_amrwb.amr"},
+
+                    // audio 10 sec, video 3 sec
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, "bbb_cif_768kbps_30fps_mpeg4" +
+                            ".mkv", "bbb_stereo_48kHz_128kbps_aac.mp4"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM, "bbb_cif_768kbps_30fps_vp9.mkv"
+                            , "bbb_stereo_48kHz_128kbps_vorbis.ogg"},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP, "bbb_cif_768kbps_30fps_h263.mp4"
+                            , "bbb_mono_8kHz_8kbps_amrnb.3gp"},
+            });
+        }
+
+        public TestMultiTrack(int outFormat, String srcFileA, String srcFileB) {
+            mOutFormat = outFormat;
+            mSrcFileA = srcFileA;
+            mSrcFileB = srcFileB;
+        }
+
+        private native boolean nativeTestMultiTrack(int format, String fileA, String fileB,
+                String fileR, String fileO);
+
+        @Test
+        public void testMultiTrack() throws IOException {
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            Assume.assumeTrue("TODO(b/146423022)",
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+            // number of times to repeat {mSrcFileA, mSrcFileB} in Output
+            final int[][] numTracks = {{2, 0}, {0, 2}, {1, 2}, {2, 1}};
+
+            MuxerTestHelper mediaInfoA = new MuxerTestHelper(mInpPathA);
+            MuxerTestHelper mediaInfoB = new MuxerTestHelper(mInpPathB);
+            assertEquals("error! unexpected track count", 1, mediaInfoA.getTrackCount());
+            assertEquals("error! unexpected track count", 1, mediaInfoB.getTrackCount());
+
+            // prepare reference
+            RandomAccessFile refFile = new RandomAccessFile(mRefPath, "rws");
+            MediaMuxer muxer = new MediaMuxer(refFile.getFD(), mOutFormat);
+            MuxerTestHelper refInfo = null;
+            String msg = String.format("testMultiTrack: inputs: %s %s, fmt: %d ", mSrcFileA,
+                    mSrcFileB, mOutFormat);
+            try {
+                mediaInfoA.combineMedias(muxer, mediaInfoB, new int[]{1, 1});
+                refInfo = new MuxerTestHelper(mRefPath);
+                if (!mediaInfoA.equals(refInfo) || !mediaInfoB.equals(refInfo)) {
+                    fail(msg + "error ! muxing src A and src B failed");
+                }
+            } catch (Exception e) {
+                if (mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG) {
+                    fail(msg + "error ! muxing src A and src B failed");
+                }
+            } finally {
+                muxer.release();
+                refFile.close();
+            }
+
+            // test multi-track
+            for (int[] numTrack : numTracks) {
+                RandomAccessFile outFile = new RandomAccessFile(mOutPath, "rws");
+                muxer = new MediaMuxer(outFile.getFD(), mOutFormat);
+                try {
+                    mediaInfoA.combineMedias(muxer, mediaInfoB, numTrack);
+                    MuxerTestHelper outInfo = new MuxerTestHelper(mOutPath);
+                    if (!outInfo.equals(refInfo)) {
+                        fail(msg + " error ! muxing src A: " + numTrack[0] + " src B: " +
+                                numTrack[1] + "failed");
+                    }
+                } catch (Exception e) {
+                    if (mOutFormat == MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) {
+                        fail(msg + " error ! muxing src A: " + numTrack[0] + " src B: " +
+                                numTrack[1] + "failed");
+                    }
+                } finally {
+                    muxer.release();
+                    outFile.close();
+                }
+            }
+        }
+
+        @Test
+        public void testMultiTrackNative() {
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            Assume.assumeTrue("TODO(b/146423022)",
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+            assertTrue(nativeTestMultiTrack(mOutFormat, mInpPathA, mInpPathB, mRefPath, mOutPath));
+        }
+    }
+
+    /**
+     * Add an offset to the presentation time of samples of a track. Mux with the added offset,
+     * validate by re-extracting the muxer output file and compare with original.
+     */
+    @Ignore("TODO(test fails for mp4, need to check if test is faulty)")
+    @LargeTest
+    @RunWith(Parameterized.class)
+    public static class TestOffsetPts {
+        private String mSrcFile;
+        private int mOutFormat;
+        private int[] mOffsetIndices;
+        private String mInpPath;
+        private String mOutPath;
+
+        static {
+            System.loadLibrary("ctsmediav2muxer_jni");
+        }
+
+        @Before
+        public void prologue() throws IOException {
+            mInpPath = WorkDir.getMediaDirString() + mSrcFile;
+            mOutPath = File.createTempFile("tmp", ".out").getAbsolutePath();
+        }
+
+        @After
+        public void epilogue() {
+            new File(mOutPath).delete();
+        }
+
+        @Parameterized.Parameters
+        public static Collection<Object[]> input() {
+            return Arrays.asList(new Object[][]{
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4,
+                            "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_aac.mp4",
+                            new int[]{0}},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM,
+                            "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm",
+                            new int[]{0}},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP,
+                            "bbb_cif_768kbps_30fps_mpeg4_mono_16kHz_20kbps_amrwb.3gp",
+                            new int[]{0}},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG, "bbb_stereo_48kHz_192kbps_opus.ogg",
+                            new int[]{10}},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, "bbb_cif_768kbps_30fps_avc.mp4",
+                            new int[]{6, 50, 77}},
+                    {MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM, "bbb_cif_768kbps_30fps_vp9.mkv",
+                            new int[]{8, 44}},
+            });
+        }
+
+        public TestOffsetPts(int outFormat, String file, int[] offsetIndices) {
+            mOutFormat = outFormat;
+            mSrcFile = file;
+            mOffsetIndices = offsetIndices;
+        }
+
+        private native boolean nativeTestOffsetPts(int format, String srcFile, String dstFile,
+                int[] offsetIndices);
+
+        @Test
+        public void testOffsetPresentationTime() throws IOException {
+            final int OFFSET_TS = 111000;
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            Assume.assumeTrue("TODO(b/146423022)",
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+            Assume.assumeTrue("TODO(b/146421018)",
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
+            assertTrue(OFFSET_TS > MuxerTestHelper.STTS_TOLERANCE);
+            MuxerTestHelper mediaInfo = new MuxerTestHelper(mInpPath);
+            for (int trackID = 0; trackID < mediaInfo.getTrackCount(); trackID++) {
+                for (int i = 0; i < mOffsetIndices.length; i++) {
+                    mediaInfo.offsetTimeStamp(trackID, OFFSET_TS, mOffsetIndices[i]);
+                }
+                MediaMuxer muxer = new MediaMuxer(mOutPath, mOutFormat);
+                mediaInfo.muxMedia(muxer);
+                muxer.release();
+                MuxerTestHelper outInfo = new MuxerTestHelper(mOutPath);
+                if (!outInfo.equals(mediaInfo)) {
+                    String msg = String.format(
+                            "testOffsetPresentationTime: inp: %s, fmt: %d, trackID %d", mSrcFile,
+                            mOutFormat, trackID);
+                    fail(msg + "error! output != input");
+                }
+                for (int i = mOffsetIndices.length - 1; i >= 0; i--) {
+                    mediaInfo.offsetTimeStamp(trackID, -OFFSET_TS, mOffsetIndices[i]);
+                }
+            }
+        }
+
+        @Test
+        public void testOffsetPresentationTimeNative() {
+            Assume.assumeTrue(shouldRunTest(mOutFormat));
+            Assume.assumeTrue("TODO(b/146423022)",
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+            Assume.assumeTrue("TODO(b/146421018)",
+                    mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
+            assertTrue(nativeTestOffsetPts(mOutFormat, mInpPath, mOutPath, mOffsetIndices));
+        }
+    }
+
+    /**
+     * Audio, Video Codecs support a variety of file-types/container formats. For example,
+     * AAC-LC supports MPEG4, 3GPP. Vorbis supports OGG and WEBM. H.263 supports 3GPP and WEBM.
+     * This test takes the output of a codec and muxes it in to all possible container formats.
+     * The results are checked for inconsistencies with the requirements of CDD.
+     */
+    @LargeTest
+    @RunWith(Parameterized.class)
+    public static class TestSimpleMux {
+        private final List<String> codecListforTypeMp4 =
+                Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
+                        MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC,
+                        MediaFormat.MIMETYPE_AUDIO_AAC);
+        private final List<String> codecListforTypeWebm =
+                Arrays.asList(MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9,
+                        MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS);
+        private final List<String> codecListforType3gp =
+                Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
+                        MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_AUDIO_AAC,
+                        MediaFormat.MIMETYPE_AUDIO_AMR_NB, MediaFormat.MIMETYPE_AUDIO_AMR_WB);
+        private final List<String> codecListforTypeOgg =
+                Arrays.asList(MediaFormat.MIMETYPE_AUDIO_OPUS);
+        private String mMime;
+        private String mSrcFile;
+        private String mInpPath;
+        private String mOutPath;
+
+        static {
+            System.loadLibrary("ctsmediav2muxer_jni");
+        }
+
+        public TestSimpleMux(String mime, String srcFile) {
+            mMime = mime;
+            mSrcFile = srcFile;
+        }
+
+        @Before
+        public void prologue() throws IOException {
+            mInpPath = WorkDir.getMediaDirString() + mSrcFile;
+            mOutPath = File.createTempFile("tmp", ".out").getAbsolutePath();
+        }
+
+        @After
+        public void epilogue() {
+            new File(mOutPath).delete();
+        }
+
+        private boolean isCodecContainerPairValid(int format) {
+            boolean result = false;
+            if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
+                result = codecListforTypeMp4.contains(mMime) || mMime.startsWith("application/");
+            else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM) {
+                return codecListforTypeWebm.contains(mMime);
+            } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP) {
+                result = codecListforType3gp.contains(mMime);
+            } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG) {
+                result = codecListforTypeOgg.contains(mMime);
+            }
+            return result;
+        }
+
+        private native boolean nativeTestSimpleMux(String srcPath, String outPath, String mime,
+                String selector);
+
+        @Parameterized.Parameters
+        public static Collection<Object[]> input() {
+            return Arrays.asList(new Object[][]{
+                    // Video Codecs
+                    {MediaFormat.MIMETYPE_VIDEO_H263,
+                            "bbb_cif_768kbps_30fps_h263_mono_8kHz_12kbps_amrnb.3gp"},
+                    {MediaFormat.MIMETYPE_VIDEO_AVC,
+                            "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_vorbis.mp4"},
+                    {MediaFormat.MIMETYPE_VIDEO_HEVC,
+                            "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_opus.mp4"},
+                    {MediaFormat.MIMETYPE_VIDEO_MPEG4,
+                            "bbb_cif_768kbps_30fps_mpeg4_mono_16kHz_20kbps_amrwb.3gp"},
+                    {MediaFormat.MIMETYPE_VIDEO_VP8,
+                            "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm"},
+                    {MediaFormat.MIMETYPE_VIDEO_VP9,
+                            "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.webm"},
+                    // Audio Codecs
+                    {MediaFormat.MIMETYPE_AUDIO_AAC,
+                            "bbb_stereo_48kHz_128kbps_aac.mp4"},
+                    {MediaFormat.MIMETYPE_AUDIO_AMR_NB,
+                            "bbb_cif_768kbps_30fps_h263_mono_8kHz_12kbps_amrnb.3gp"},
+                    {MediaFormat.MIMETYPE_AUDIO_AMR_WB,
+                            "bbb_cif_768kbps_30fps_mpeg4_mono_16kHz_20kbps_amrwb.3gp"},
+                    {MediaFormat.MIMETYPE_AUDIO_OPUS,
+                            "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.webm"},
+                    {MediaFormat.MIMETYPE_AUDIO_VORBIS,
+                            "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm"},
+                    // Metadata
+                    {"application/gyro",
+                            "video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro_non_compliant.3gp"},
+                    {"application/gyro",
+                            "video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro_compliant.3gp"},
+            });
+        }
+
+        @Test
+        public void testSimpleMux() throws IOException {
+            Assume.assumeTrue("TODO(b/146421018)",
+                    !mMime.equals(MediaFormat.MIMETYPE_AUDIO_OPUS));
+            Assume.assumeTrue("TODO(b/146923287)",
+                    !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS));
+            MuxerTestHelper mediaInfo = new MuxerTestHelper(mInpPath, mMime);
+            assertEquals("error! unexpected track count", 1, mediaInfo.getTrackCount());
+            for (int format = MUXER_OUTPUT_FIRST; format <= MUXER_OUTPUT_LAST; format++) {
+                if (!shouldRunTest(format)) continue;
+                // TODO(b/146923551)
+                if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM) continue;
+                String msg = String.format("testSimpleMux: inp: %s, mime: %s, fmt: %d ", mSrcFile,
+                        mMime, format);
+                MediaMuxer muxer = new MediaMuxer(mOutPath, format);
+                try {
+                    mediaInfo.muxMedia(muxer);
+                    MuxerTestHelper outInfo = new MuxerTestHelper(mOutPath);
+                    if (!mediaInfo.equals(outInfo)) {
+                        fail(msg + "error! output != clone(input)");
+                    }
+                } catch (Exception e) {
+                    if (isCodecContainerPairValid(format)) {
+                        fail(msg + "error! incompatible mime and output format");
+                    }
+                } finally {
+                    muxer.release();
+                }
+            }
+        }
+
+        @Test
+        public void testSimpleMuxNative() {
+            Assume.assumeTrue("TODO(b/146421018)",
+                    !mMime.equals(MediaFormat.MIMETYPE_AUDIO_OPUS));
+            Assume.assumeTrue("TODO(b/146923287)",
+                    !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS));
+            assertTrue(nativeTestSimpleMux(mInpPath, mOutPath, mMime, selector));
+        }
+    }
+}
diff --git a/tests/signature/api-check/system-annotation/AndroidTest.xml b/tests/signature/api-check/system-annotation/AndroidTest.xml
index 43183bf..691516c 100644
--- a/tests/signature/api-check/system-annotation/AndroidTest.xml
+++ b/tests/signature/api-check/system-annotation/AndroidTest.xml
@@ -28,7 +28,7 @@
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.AnnotationTest" />
         <option name="instrumentation-arg" key="expected-api-files" value="system-current.txt,system-removed.txt,car-system-current.txt,car-system-removed.txt" />
-        <option name="instrumentation-arg" key="annotation-for-exact-match" value="android.annotation.SystemApi" />
+        <option name="instrumentation-arg" key="annotation-for-exact-match" value="@android.annotation.SystemApi\(client=PRIVILEGED_APPS,\ process=ALL\)" />
         <option name="runtime-hint" value="30s" />
     </test>
 
diff --git a/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java b/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java
index ab111a4..cd6db94 100644
--- a/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java
@@ -28,7 +28,7 @@
  */
 public class AnnotationChecker extends AbstractApiChecker {
 
-    private final Class<? extends Annotation> annotationClass;
+    private final String annotationSpec;
 
     private final Map<String, Class<?>> annotatedClassesMap = new HashMap<>();
     private final Map<String, Set<Constructor<?>>> annotatedConstructorsMap = new HashMap<>();
@@ -40,24 +40,24 @@
      *      android.annotation.SystemApi)
      */
     public AnnotationChecker(
-            ResultObserver resultObserver, ClassProvider classProvider, String annotationName) {
+            ResultObserver resultObserver, ClassProvider classProvider, String annotationSpec) {
         super(classProvider, resultObserver);
 
-        annotationClass = ReflectionHelper.getAnnotationClass(annotationName);
+        this.annotationSpec = annotationSpec;
         classProvider.getAllClasses().forEach(clazz -> {
-            if (clazz.isAnnotationPresent(annotationClass)) {
+            if (ReflectionHelper.hasMatchingAnnotation(clazz, annotationSpec)) {
                 annotatedClassesMap.put(clazz.getName(), clazz);
             }
             Set<Constructor<?>> constructors = ReflectionHelper.getAnnotatedConstructors(clazz,
-                    annotationClass);
+                    annotationSpec);
             if (!constructors.isEmpty()) {
                 annotatedConstructorsMap.put(clazz.getName(), constructors);
             }
-            Set<Method> methods = ReflectionHelper.getAnnotatedMethods(clazz, annotationClass);
+            Set<Method> methods = ReflectionHelper.getAnnotatedMethods(clazz, annotationSpec);
             if (!methods.isEmpty()) {
                 annotatedMethodsMap.put(clazz.getName(), methods);
             }
-            Set<Field> fields = ReflectionHelper.getAnnotatedFields(clazz, annotationClass);
+            Set<Field> fields = ReflectionHelper.getAnnotatedFields(clazz, annotationSpec);
             if (!fields.isEmpty()) {
                 annotatedFieldsMap.put(clazz.getName(), fields);
             }
@@ -68,27 +68,27 @@
     public void checkDeferred() {
         for (Class<?> clazz : annotatedClassesMap.values()) {
             resultObserver.notifyFailure(FailureType.EXTRA_CLASS, clazz.getName(),
-                    "Class annotated with " + annotationClass.getName()
+                    "Class annotated with " + annotationSpec
                             + " does not exist in the documented API");
         }
         for (Set<Constructor<?>> set : annotatedConstructorsMap.values()) {
             for (Constructor<?> c : set) {
                 resultObserver.notifyFailure(FailureType.EXTRA_METHOD, c.toString(),
-                        "Constructor annotated with " + annotationClass.getName()
+                        "Constructor annotated with " + annotationSpec
                                 + " does not exist in the API");
             }
         }
         for (Set<Method> set : annotatedMethodsMap.values()) {
             for (Method m : set) {
                 resultObserver.notifyFailure(FailureType.EXTRA_METHOD, m.toString(),
-                        "Method annotated with " + annotationClass.getName()
+                        "Method annotated with " + annotationSpec
                                 + " does not exist in the API");
             }
         }
         for (Set<Field> set : annotatedFieldsMap.values()) {
             for (Field f : set) {
                 resultObserver.notifyFailure(FailureType.EXTRA_FIELD, f.toString(),
-                        "Field annotated with " + annotationClass.getName()
+                        "Field annotated with " + annotationSpec
                                 + " does not exist in the API");
             }
         }
@@ -116,10 +116,10 @@
     protected void checkField(JDiffClassDescription classDescription, Class<?> runtimeClass,
             JDiffClassDescription.JDiffField fieldDescription, Field field) {
         // make sure that the field (or its declaring class) is annotated
-        if (!ReflectionHelper.isAnnotatedOrInAnnotatedClass(field, annotationClass)) {
+        if (!ReflectionHelper.isAnnotatedOrInAnnotatedClass(field, annotationSpec)) {
             resultObserver.notifyFailure(FailureType.MISSING_ANNOTATION,
                     field.toString(),
-                    "Annotation " + annotationClass.getName() + " is missing");
+                    "Annotation " + annotationSpec + " is missing");
         }
 
         // remove it from the set if found in the API doc
@@ -136,11 +136,11 @@
                 .get(runtimeClass.getName());
 
         // make sure that the constructor (or its declaring class) is annotated
-        if (annotationClass != null) {
-            if (!ReflectionHelper.isAnnotatedOrInAnnotatedClass(ctor, annotationClass)) {
+        if (annotationSpec != null) {
+            if (!ReflectionHelper.isAnnotatedOrInAnnotatedClass(ctor, annotationSpec)) {
                 resultObserver.notifyFailure(FailureType.MISSING_ANNOTATION,
                         ctor.toString(),
-                        "Annotation " + annotationClass.getName() + " is missing");
+                        "Annotation " + annotationSpec + " is missing");
             }
         }
 
@@ -155,12 +155,12 @@
             JDiffClassDescription.JDiffMethod methodDescription, Method method) {
         // make sure that the method (or its declaring class) is annotated or overriding
         // annotated method.
-        if (!ReflectionHelper.isAnnotatedOrInAnnotatedClass(method, annotationClass)
+        if (!ReflectionHelper.isAnnotatedOrInAnnotatedClass(method, annotationSpec)
                 && !ReflectionHelper.isOverridingAnnotatedMethod(method,
-                        annotationClass)) {
+                        annotationSpec)) {
             resultObserver.notifyFailure(FailureType.MISSING_ANNOTATION,
                     method.toString(),
-                    "Annotation " + annotationClass.getName() + " is missing");
+                    "Annotation " + annotationSpec + " is missing");
         }
 
         // remove it from the set if found in the API doc
diff --git a/tests/signature/lib/common/src/android/signature/cts/DexMethod.java b/tests/signature/lib/common/src/android/signature/cts/DexMethod.java
index 9f209fe..dfe1934 100644
--- a/tests/signature/lib/common/src/android/signature/cts/DexMethod.java
+++ b/tests/signature/lib/common/src/android/signature/cts/DexMethod.java
@@ -23,6 +23,7 @@
 
 public class DexMethod extends DexMember {
   private final List<String> mParamTypeList;
+  private static final Pattern REGEX_SIGNATURE = Pattern.compile("^\\((.*)\\)(.*)$");
 
   public DexMethod(String className, String name, String signature, String[] flags) {
       super(className, name, parseDexReturnType(signature), flags);
@@ -52,7 +53,7 @@
   }
 
   private static Matcher matchSignature(String signature) {
-      Matcher m = Pattern.compile("^\\((.*)\\)(.*)$").matcher(signature);
+      Matcher m = REGEX_SIGNATURE.matcher(signature);
       if (!m.matches()) {
           throw new RuntimeException("Could not parse method signature: " + signature);
       }
diff --git a/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java b/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
index 6b6140a..9c3741e 100644
--- a/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
+++ b/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
@@ -18,6 +18,7 @@
 import android.signature.cts.JDiffClassDescription.JDiffConstructor;
 import android.signature.cts.JDiffClassDescription.JDiffMethod;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.GenericArrayType;
@@ -420,33 +421,24 @@
         }
     }
 
-    /**
-     * Returns a Class representing an annotation type of the given name.
-     */
-    @SuppressWarnings("unchecked")
-    public static Class<? extends Annotation> getAnnotationClass(String name) {
-        try {
-            Class<?> clazz = Class.forName(
-                    name, false, ReflectionHelper.class.getClassLoader());
-            if (clazz.isAnnotation()) {
-                return (Class<? extends Annotation>) clazz;
-            } else {
-                return null;
+    public static boolean hasMatchingAnnotation(AnnotatedElement elem, String annotationSpec) {
+        for (Annotation a : elem.getAnnotations()) {
+            if (a.toString().equals(annotationSpec)) {
+                return true;
             }
-        } catch (ClassNotFoundException e) {
-            return null;
         }
+        return false;
     }
 
     /**
      * Returns a list of constructors which are annotated with the given annotation class.
      */
     public static Set<Constructor<?>> getAnnotatedConstructors(Class<?> clazz,
-            Class<? extends Annotation> annotation) {
+            String annotationSpec) {
         Set<Constructor<?>> result = new HashSet<>();
-        if (annotation != null) {
+        if (annotationSpec != null) {
             for (Constructor<?> c : clazz.getDeclaredConstructors()) {
-                if (c.isAnnotationPresent(annotation)) {
+                if (hasMatchingAnnotation(c, annotationSpec)) {
                     // TODO(b/71630695): currently, some API members are not annotated, because
                     // a member is automatically added to the API set if it is in a class with
                     // annotation and it is not @hide. <member>.getDeclaringClass().
@@ -464,12 +456,11 @@
     /**
      * Returns a list of methods which are annotated with the given annotation class.
      */
-    public static Set<Method> getAnnotatedMethods(Class<?> clazz,
-            Class<? extends Annotation> annotation) {
+    public static Set<Method> getAnnotatedMethods(Class<?> clazz, String annotationSpec) {
         Set<Method> result = new HashSet<>();
-        if (annotation != null) {
+        if (annotationSpec != null) {
             for (Method m : clazz.getDeclaredMethods()) {
-                if (m.isAnnotationPresent(annotation)) {
+                if (hasMatchingAnnotation(m, annotationSpec)) {
                     // TODO(b/71630695): see getAnnotatedConstructors for details
                     result.add(m);
                 }
@@ -481,12 +472,11 @@
     /**
      * Returns a list of fields which are annotated with the given annotation class.
      */
-    public static Set<Field> getAnnotatedFields(Class<?> clazz,
-            Class<? extends Annotation> annotation) {
+    public static Set<Field> getAnnotatedFields(Class<?> clazz, String annotationSpec) {
         Set<Field> result = new HashSet<>();
-        if (annotation != null) {
+        if (annotationSpec != null) {
             for (Field f : clazz.getDeclaredFields()) {
-                if (f.isAnnotationPresent(annotation)) {
+                if (hasMatchingAnnotation(f, annotationSpec)) {
                     // TODO(b/71630695): see getAnnotatedConstructors for details
                     result.add(f);
                 }
@@ -495,46 +485,42 @@
         return result;
     }
 
-    private static boolean isInAnnotatedClass(Member m,
-            Class<? extends Annotation> annotationClass) {
+    private static boolean isInAnnotatedClass(Member m, String annotationSpec) {
         Class<?> clazz = m.getDeclaringClass();
         do {
-            if (clazz.isAnnotationPresent(annotationClass)) {
+            if (hasMatchingAnnotation(clazz, annotationSpec)) {
                 return true;
             }
         } while ((clazz = clazz.getDeclaringClass()) != null);
         return false;
     }
 
-    public static boolean isAnnotatedOrInAnnotatedClass(Field field,
-            Class<? extends Annotation> annotationClass) {
-        if (annotationClass == null) {
+    public static boolean isAnnotatedOrInAnnotatedClass(Field field, String annotationSpec) {
+        if (annotationSpec == null) {
             return true;
         }
-        return field.isAnnotationPresent(annotationClass)
-                || isInAnnotatedClass(field, annotationClass);
+        return hasMatchingAnnotation(field, annotationSpec)
+                || isInAnnotatedClass(field, annotationSpec);
     }
 
     public static boolean isAnnotatedOrInAnnotatedClass(Constructor<?> constructor,
-            Class<? extends Annotation> annotationClass) {
-        if (annotationClass == null) {
+            String annotationSpec) {
+        if (annotationSpec == null) {
             return true;
         }
-        return constructor.isAnnotationPresent(annotationClass)
-                || isInAnnotatedClass(constructor, annotationClass);
+        return hasMatchingAnnotation(constructor, annotationSpec)
+                || isInAnnotatedClass(constructor, annotationSpec);
     }
 
-    public static boolean isAnnotatedOrInAnnotatedClass(Method method,
-            Class<? extends Annotation> annotationClass) {
-        if (annotationClass == null) {
+    public static boolean isAnnotatedOrInAnnotatedClass(Method method, String annotationSpec) {
+        if (annotationSpec == null) {
             return true;
         }
-        return method.isAnnotationPresent(annotationClass)
-                || isInAnnotatedClass(method, annotationClass);
+        return hasMatchingAnnotation(method, annotationSpec)
+                || isInAnnotatedClass(method, annotationSpec);
     }
 
-    public static boolean isOverridingAnnotatedMethod(Method method,
-            Class<? extends Annotation> annotationClass) {
+    public static boolean isOverridingAnnotatedMethod(Method method, String annotationSpec) {
         Class<?> clazz = method.getDeclaringClass();
         while (!(clazz = clazz.getSuperclass()).equals(Object.class)) {
             try {
@@ -542,7 +528,7 @@
                 overriddenMethod = clazz.getDeclaredMethod(method.getName(),
                         method.getParameterTypes());
                 if (overriddenMethod != null) {
-                    return isAnnotatedOrInAnnotatedClass(overriddenMethod, annotationClass);
+                    return isAnnotatedOrInAnnotatedClass(overriddenMethod, annotationSpec);
                 }
             } catch (NoSuchMethodException e) {
                 continue;
diff --git a/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
index 7682a50..90dada9 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
@@ -37,7 +37,8 @@
     @Override
     protected AnnotationChecker createChecker(ResultObserver resultObserver,
             ClassProvider provider) {
-        return new AnnotationChecker(resultObserver, provider, ApiAnnotation.class.getName());
+        return new AnnotationChecker(resultObserver, provider,
+                "@android.signature.cts.tests.data.ApiAnnotation()");
     }
 
     private static void addConstructor(JDiffClassDescription clz, String... paramTypes) {
diff --git a/tests/tests/app/src/android/app/cts/KeyguardInitialLockTest.java b/tests/tests/app/src/android/app/cts/KeyguardInitialLockTest.java
new file mode 100644
index 0000000..244621b
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/KeyguardInitialLockTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package android.app;
+
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+
+import java.util.List;
+
+public class KeyguardInitialLockTest extends AndroidTestCase {
+
+    public void testSetInitialLockPermission() {
+        final ArraySet<String> allowedPackages = new ArraySet();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
+        PackageManager pm = getContext().getPackageManager();
+        final List<ResolveInfo> activities =
+                pm.queryIntentActivities(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
+        String validPkg = "";
+        for (ResolveInfo ri : activities) {
+            if (ri != null) {
+                allowedPackages.add(ri.activityInfo.packageName);
+                validPkg = ri.activityInfo.packageName;
+            }
+        }
+        final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[]{
+                android.Manifest.permission.SET_INITIAL_LOCK
+        }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+        for (PackageInfo pi : holding) {
+            if (!allowedPackages.contains(pi.packageName)) {
+                fail("The SET_INITIAL_LOCK permission must not be held by " + pi.packageName
+                        + " and must be revoked for security reasons [" + validPkg + "]");
+            }
+        }
+    }
+}
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 8e243c9..81149f0 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -106,7 +106,6 @@
             QUERIES_NOTHING_SHARED_USER
     };
 
-    private static Context sContext;
     private static Handler sResponseHandler;
     private static HandlerThread sResponseThread;
 
@@ -138,10 +137,6 @@
     @Before
     public void setupTest() {
         if (!sGlobalFeatureEnabled) return;
-
-        if (sContext == null) {
-            sContext = InstrumentationRegistry.getInstrumentation().getContext();
-        }
         setFeatureEnabledForAll(true);
     }
 
@@ -319,7 +314,7 @@
                 },
                 sResponseHandler);
         intent.putExtra("remoteCallback", callback);
-        sContext.startActivity(intent);
+        InstrumentationRegistry.getInstrumentation().getContext().startActivity(intent);
         if (!latch.block(TimeUnit.SECONDS.toMillis(10))) {
             throw new TimeoutException(
                     "Latch timed out while awiating a response from " + targetPackageName);
diff --git a/tests/tests/bionic/Android.build.copy.libs.mk b/tests/tests/bionic/Android.build.copy.libs.mk
index d933bbc..5867547 100644
--- a/tests/tests/bionic/Android.build.copy.libs.mk
+++ b/tests/tests/bionic/Android.build.copy.libs.mk
@@ -43,6 +43,9 @@
   libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip \
   libdlext_test_zip/libdlext_test_zip.so \
   libdlext_test_zip/libdlext_test_zip_zipaligned.zip \
+  libgnu-hash-table-library.so \
+  librelr-new.so \
+  librelr-old.so \
   libsegment_gap_inner.so \
   libsegment_gap_outer.so \
   libsysv-hash-table-library.so \
@@ -88,6 +91,9 @@
   libtest_elftls_shared_var_ie.so \
   libtest_elftls_tprel.so \
   libtest_empty.so \
+  libtest_ifunc.so \
+  libtest_ifunc_variable.so \
+  libtest_ifunc_variable_impl.so \
   libtest_indirect_thread_local_dtor.so \
   libtest_init_fini_order_child.so \
   libtest_init_fini_order_grand_child.so \
@@ -150,13 +156,6 @@
   public_namespace_libs/libtest_missing_symbol.so \
   public_namespace_libs/libtest_missing_symbol_child_public.so \
 
-# These libraries are not built for mips.
-my_bionic_testlib_files_non_mips := \
-  libgnu-hash-table-library.so \
-  libtest_ifunc.so \
-  libtest_ifunc_variable.so \
-  libtest_ifunc_variable_impl.so \
-
 my_bionic_testlibs_src_dir := \
   $($(cts_bionic_tests_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs
 my_bionic_testlibs_out_dir := $(cts_bionic_tests_dir)/bionic-loader-test-libs
@@ -165,12 +164,6 @@
   $(foreach lib, $(my_bionic_testlib_files), \
     $(my_bionic_testlibs_src_dir)/$(lib):$(my_bionic_testlibs_out_dir)/$(lib))
 
-ifneq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),mips mips64))
-LOCAL_COMPATIBILITY_SUPPORT_FILES += \
-  $(foreach lib, $(my_bionic_testlib_files_non_mips), \
-    $(my_bionic_testlibs_src_dir)/$(lib):$(my_bionic_testlibs_out_dir)/$(lib))
-endif
-
 # Special casing for libtest_dt_runpath_y.so. Since we use the standard ARM CTS
 # to test ARM-on-x86 devices where ${LIB} is expanded to lib/arm, the lib
 # is installed to ./lib/arm as well as ./lib to make sure that the lib can be
@@ -186,7 +179,6 @@
 LOCAL_COMPATIBILITY_SUPPORT_FILES += $(src):$(dst)
 
 my_bionic_testlib_files :=
-my_bionic_testlib_files_non_mips :=
 my_bionic_testlibs_src_dir :=
 my_bionic_testlibs_out_dir :=
 cts_bionic_tests_dir :=
diff --git a/tests/tests/carrierapi/AndroidManifest.xml b/tests/tests/carrierapi/AndroidManifest.xml
index 978651f..52057ac 100644
--- a/tests/tests/carrierapi/AndroidManifest.xml
+++ b/tests/tests/carrierapi/AndroidManifest.xml
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/tests/content/pm/OWNERS b/tests/tests/content/pm/OWNERS
new file mode 100644
index 0000000..941653d
--- /dev/null
+++ b/tests/tests/content/pm/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36137
+patb@google.com
+toddke@google.com
+narayan@google.com
diff --git a/tests/tests/rcs/Android.bp b/tests/tests/content/pm/SecureFrp/Android.bp
similarity index 64%
rename from tests/tests/rcs/Android.bp
rename to tests/tests/content/pm/SecureFrp/Android.bp
index 5de3331..91abdc6 100644
--- a/tests/tests/rcs/Android.bp
+++ b/tests/tests/content/pm/SecureFrp/Android.bp
@@ -1,10 +1,10 @@
-// Copyright (C) 2019 The Android Open Source Project
+// 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
+// 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,
@@ -13,23 +13,23 @@
 // limitations under the License.
 
 android_test {
-    name: "CtsRcsTestCases",
-    defaults: ["cts_defaults"],
+    name: "CtsSecureFrpInstallTestCases",
+
+    srcs:  ["src/**/*.java"],
+
     static_libs: [
-        "compatibility-device-util-axt",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "cts-install-lib",
     ],
-    libs: [
-        "android.test.runner.stubs",
-        "android.test.base.stubs",
-    ],
-    srcs: ["src/**/*.java"],
-    // Tag this module as a cts test artifact
+
+    sdk_version: "test_current",
+
     test_suites: [
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
-    platform_apis: true,
 }
diff --git a/tests/tests/content/pm/SecureFrp/AndroidManifest.xml b/tests/tests/content/pm/SecureFrp/AndroidManifest.xml
new file mode 100644
index 0000000..f1b5184
--- /dev/null
+++ b/tests/tests/content/pm/SecureFrp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?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.tests.securefrpinstall" >
+
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+    <application>
+        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
+                  android:exported="true" />
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.tests.securefrpinstall"
+                     android:label="AtomicInstall Test"/>
+
+</manifest>
diff --git a/tests/tests/content/pm/SecureFrp/AndroidTest.xml b/tests/tests/content/pm/SecureFrp/AndroidTest.xml
new file mode 100644
index 0000000..bd0ce82
--- /dev/null
+++ b/tests/tests/content/pm/SecureFrp/AndroidTest.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+<configuration description="Runs the secure FRP install tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <!-- Instant apps can't install packages. -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+    <!-- target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/cts/pm" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/cts"/>
+    </target_preparer -->
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSecureFrpInstallTestCases.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+        <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+    </target_preparer>
+
+    <!-- target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="TestAppAv1.apk->/data/local/tmp/cts/pm/TestAppAv1.apk" />
+    </target_preparer -->
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.tests.securefrpinstall" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/tests/tests/content/pm/SecureFrp/TEST_MAPPING b/tests/tests/content/pm/SecureFrp/TEST_MAPPING
new file mode 100644
index 0000000..c87e54e
--- /dev/null
+++ b/tests/tests/content/pm/SecureFrp/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsSecureFrpInstallTestCases"
+    }
+  ]
+}
diff --git a/tests/tests/content/pm/SecureFrp/src/com/android/tests/securefrpinstall/SecureFrpInstallTest.java b/tests/tests/content/pm/SecureFrp/src/com/android/tests/securefrpinstall/SecureFrpInstallTest.java
new file mode 100644
index 0000000..2f1dfc7
--- /dev/null
+++ b/tests/tests/content/pm/SecureFrp/src/com/android/tests/securefrpinstall/SecureFrpInstallTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+package com.android.tests.atomicinstall;
+
+import static org.junit.Assert.fail;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for package installation while Secure FRP mode is enabled. */
+@RunWith(JUnit4.class)
+public class SecureFrpInstallTest {
+
+    private static PackageManager sPackageManager;
+
+    private static void adoptShellPermissions() {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity(
+                        Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES);
+    }
+
+    private static void dropShellPermissions() {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    private static void setSecureFrp(boolean secureFrp) throws Exception {
+        adoptShellPermissions();
+        SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
+                "settings put secure secure_frp_mode " + (secureFrp ? "1" : "0"));
+        dropShellPermissions();
+    }
+
+    private static void assertInstalled() throws Exception {
+        sPackageManager.getPackageInfo(TestApp.A, 0);
+    }
+
+    private static void assertNotInstalled() {
+        try {
+            sPackageManager.getPackageInfo(TestApp.A, 0);
+            fail("Package should not be installed");
+        } catch (PackageManager.NameNotFoundException expected) {
+        }
+    }
+
+    @BeforeClass
+    public static void initialize() {
+        sPackageManager = InstrumentationRegistry
+                .getInstrumentation()
+                .getContext()
+                .getPackageManager();
+    }
+
+    @Before
+    public void setup() throws Exception {
+        adoptShellPermissions();
+        Uninstall.packages(TestApp.A);
+        dropShellPermissions();
+    }
+
+    @After
+    public void teardown() throws Exception {
+        dropShellPermissions();
+        setSecureFrp(false);
+    }
+
+    /** Tests a SecurityException is thrown while in secure FRP mode. */
+    @Test
+    public void testPackageInstallApi() throws Exception {
+        setSecureFrp(true);
+        try {
+            Install.single(TestApp.A1).commit();
+            fail("Expected a SecurityException");
+        } catch (SecurityException expected) {
+        }
+        assertNotInstalled();
+    }
+
+    /** Tests can install when granted INSTALL_PACKAGES permission; even in secure FRP mode. */
+    @Test
+    public void testPackageInstallApiAsShell() throws Exception {
+        setSecureFrp(true);
+        adoptShellPermissions();
+        Install.single(TestApp.A1).commit();
+        dropShellPermissions();
+        assertInstalled();
+    }
+}
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index 00e6b32..972994f 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -42,6 +42,7 @@
 import java.io.OutputStream;
 import java.util.Arrays;
 import java.util.Optional;
+import java.util.Random;
 import java.util.stream.Collectors;
 
 @RunWith(Parameterized.class)
@@ -148,12 +149,35 @@
     }
 
     @Test
+    public void testAppInstallErr() throws Exception {
+        if (!mStreaming) {
+            return;
+        }
+        File file = new File(createApkPath(TEST_HW5));
+        String command = "pm " + mInstall + " -t -g " + file.getPath() + (new Random()).nextLong();
+        String commandResult = executeShellCommand(command);
+        assertEquals("Failure [INSTALL_FAILED_MEDIA_UNAVAILABLE: Failed to prepare image.]\n",
+                commandResult);
+        assertFalse(isAppInstalled(TEST_APP_PACKAGE));
+    }
+
+    @Test
     public void testAppInstallStdIn() throws Exception {
         installPackageStdIn(TEST_HW5);
         assertTrue(isAppInstalled(TEST_APP_PACKAGE));
     }
 
     @Test
+    public void testAppInstallStdInErr() throws Exception {
+        File file = new File(createApkPath(TEST_HW5));
+        String commandResult = executeShellCommand("pm " + mInstall + " -t -g -S " + file.length(),
+                new File[]{});
+        assertTrue(commandResult,
+                commandResult.startsWith("Failure [INSTALL_PARSE_FAILED_NOT_APK"));
+        assertFalse(isAppInstalled(TEST_APP_PACKAGE));
+    }
+
+    @Test
     public void testAppUpdate() throws Exception {
         installPackage(TEST_HW5);
         assertTrue(isAppInstalled(TEST_APP_PACKAGE));
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index 82abb58..98c392a 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -29,6 +29,14 @@
             android:label="CameraGpuCtsActivity">
         </activity>
 
+        <activity android:name="android.graphics.cts.FrameRateCtsActivity"
+            android:label="FrameRateCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.graphics.cts.ImageViewCtsActivity"
             android:label="ImageViewCtsActivity">
             <intent-filter>
diff --git a/tests/tests/graphics/jni/Android.bp b/tests/tests/graphics/jni/Android.bp
index 0a302de..87105a2 100644
--- a/tests/tests/graphics/jni/Android.bp
+++ b/tests/tests/graphics/jni/Android.bp
@@ -22,6 +22,7 @@
         "android_graphics_cts_ASurfaceTextureTest.cpp",
         "android_graphics_cts_BasicVulkanGpuTest.cpp",
         "android_graphics_cts_BitmapTest.cpp",
+        "android_graphics_cts_FrameRateCtsActivity.cpp",
         "android_graphics_cts_SyncTest.cpp",
         "android_graphics_cts_CameraGpuCtsActivity.cpp",
         "android_graphics_cts_CameraVulkanGpuTest.cpp",
diff --git a/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp b/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp
index 1d7dd89..050f403 100644
--- a/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp
+++ b/tests/tests/graphics/jni/CtsGraphicsJniOnLoad.cpp
@@ -24,6 +24,7 @@
 extern int register_android_graphics_cts_BitmapTest(JNIEnv*);
 extern int register_android_graphics_cts_CameraGpuCtsActivity(JNIEnv*);
 extern int register_android_graphics_cts_CameraVulkanGpuTest(JNIEnv*);
+extern int register_android_graphics_cts_FrameRateCtsActivity(JNIEnv*);
 extern int register_android_graphics_cts_MediaVulkanGpuTest(JNIEnv*);
 extern int register_android_graphics_cts_VulkanFeaturesTest(JNIEnv*);
 extern int register_android_graphics_cts_VulkanPreTransformCtsActivity(JNIEnv*);
@@ -46,6 +47,8 @@
         return JNI_ERR;
     if (register_android_graphics_cts_CameraVulkanGpuTest(env))
         return JNI_ERR;
+    if (register_android_graphics_cts_FrameRateCtsActivity(env))
+        return JNI_ERR;
     if (register_android_graphics_cts_MediaVulkanGpuTest(env))
         return JNI_ERR;
     if (register_android_graphics_cts_VulkanFeaturesTest(env))
diff --git a/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp b/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp
index 01096c4..637cecb 100644
--- a/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp
+++ b/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp
@@ -34,6 +34,7 @@
 #include <memory>
 #include <stdio.h>
 #include <unistd.h>
+#include <vector>
 
 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 
@@ -146,7 +147,6 @@
     ASSERT_EQ(0, AImageDecoderHeaderInfo_getWidth(nullptr));
     ASSERT_EQ(0, AImageDecoderHeaderInfo_getHeight(nullptr));
     ASSERT_EQ(nullptr, AImageDecoderHeaderInfo_getMimeType(nullptr));
-    ASSERT_EQ(false, AImageDecoderHeaderInfo_isAnimated(nullptr));
     ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, AImageDecoderHeaderInfo_getDataSpace(nullptr));
 
     {
@@ -169,7 +169,7 @@
 }
 
 static void testInfo(JNIEnv* env, jclass, jlong imageDecoderPtr, jint width, jint height,
-                     jstring jMimeType, jboolean isAnimated, jboolean isF16, jint dataSpace) {
+                     jstring jMimeType, jboolean isF16, jint dataSpace) {
     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
     ASSERT_NE(decoder, nullptr);
     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
@@ -185,7 +185,6 @@
     ASSERT_NE(mimeType, nullptr);
     ASSERT_EQ(0, strcmp(mimeType, AImageDecoderHeaderInfo_getMimeType(info)));
     env->ReleaseStringUTFChars(jMimeType, mimeType);
-    ASSERT_EQ(isAnimated, AImageDecoderHeaderInfo_isAnimated(info));
     auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
     if (isF16) {
         ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_F16, format);
@@ -366,7 +365,7 @@
     }
 }
 
-static int bytesPerPixel(AndroidBitmapFormat format) {
+static int bytesPerPixel(int32_t format) {
     switch (format) {
         case ANDROID_BITMAP_FORMAT_RGBA_8888:
             return 4;
@@ -378,6 +377,7 @@
             return 8;
         case ANDROID_BITMAP_FORMAT_NONE:
         case ANDROID_BITMAP_FORMAT_RGBA_4444:
+        default:
             return 0;
     }
 }
@@ -455,14 +455,14 @@
         return false;           \
     }
 
-static bool bitmapsEqual(JNIEnv* env, jobject jbitmap, AndroidBitmapFormat format,
+static bool bitmapsEqual(JNIEnv* env, jobject jbitmap, int32_t androidBitmapFormat,
                          int width, int height, int alphaFlags, size_t minStride,
                          void* pixelsA, size_t strideA) {
     AndroidBitmapInfo jInfo;
     int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
     EXPECT_EQ("Failed to getInfo on Bitmap", ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
 
-    EXPECT_EQ("Wrong format", jInfo.format, format);
+    EXPECT_EQ("Wrong format", jInfo.format, androidBitmapFormat);
 
     // If the image is truly opaque, the Java Bitmap will report OPAQUE, even if
     // the AImageDecoder requested PREMUL/UNPREMUL. In that case, it is okay for
@@ -613,26 +613,62 @@
     ASSERT_NE(info, nullptr);
 
     const int height = AImageDecoderHeaderInfo_getHeight(info);
-    size_t minStride = AImageDecoder_getMinimumStride(decoder);
+    const int origWidth = AImageDecoderHeaderInfo_getWidth(info);
 
-    void* pixels = nullptr;
-
-    // The code in this loop relies on minStride being used first.
-    for (size_t stride : { minStride, minStride * 2, minStride * 3 }) {
-        size_t size = stride * (height - 1) + minStride;
-        void* decodePixels = malloc(size);
-        int result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
+    for (int width : { origWidth, origWidth / 3 }) {
+        if (width == 0) {
+            // The 1 x 1 image cannot be downscaled.
+            continue;
+        }
+        int result = AImageDecoder_setTargetSize(decoder, width, height);
         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
+        for (AndroidBitmapFormat format : {
+            ANDROID_BITMAP_FORMAT_RGBA_8888,
+            ANDROID_BITMAP_FORMAT_RGB_565,
+            ANDROID_BITMAP_FORMAT_A_8,
+            ANDROID_BITMAP_FORMAT_RGBA_F16,
+        }) {
+            result = AImageDecoder_setAndroidBitmapFormat(decoder, format);
+            if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
+                // Not all images can be decoded to all formats. This is okay, and
+                // we've tested that we can decode to the expected formats elsewhere.
+                continue;
+            }
 
-        if (pixels == nullptr) {
-            pixels = decodePixels;
-        } else {
-            ASSERT_TRUE(bitmapsEqual(minStride, height, pixels, minStride, decodePixels, stride));
-            free(decodePixels);
+            size_t minStride = AImageDecoder_getMinimumStride(decoder);
+            void* pixels = nullptr;
+
+            // The code in the below loop relies on minStride being used first.
+            std::vector<size_t> strides;
+            strides.push_back(minStride);
+            for (int i = 1; i <= 16; i++) {
+                strides.push_back(i + minStride);
+            }
+            strides.push_back(minStride * 2);
+            strides.push_back(minStride * 3);
+            for (size_t stride : strides) {
+                size_t size = stride * (height - 1) + minStride;
+                void* decodePixels = malloc(size);
+                result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
+                if ((stride - minStride) % bytesPerPixel(format) != 0) {
+                    // The stride is not pixel aligned.
+                    ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
+                    continue;
+                }
+                ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
+
+                if (pixels == nullptr) {
+                    pixels = decodePixels;
+                } else {
+                    ASSERT_TRUE(bitmapsEqual(minStride, height, pixels, minStride, decodePixels,
+                                             stride));
+                    free(decodePixels);
+                }
+            }
+
+            free(pixels);
         }
     }
-
-    free(pixels);
 }
 
 static void testSetTargetSize(JNIEnv* env, jclass, jlong imageDecoderPtr) {
@@ -641,14 +677,14 @@
 
     const size_t defaultStride = AImageDecoder_getMinimumStride(decoder);
 
-    for (int width : { -1, 0, -500 }) {
+    for (int32_t width : { -1, 0, -500 }) {
         int result = AImageDecoder_setTargetSize(decoder, width, 100);
         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
         // stride is unchanged, as the target size did not change.
         ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
     }
 
-    for (int height : { -1, 0, -300 }) {
+    for (int32_t height : { -1, 0, -300 }) {
         int result = AImageDecoder_setTargetSize(decoder, 100, height);
         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
         // stride is unchanged, as the target size did not change.
@@ -659,7 +695,7 @@
     ASSERT_NE(info, nullptr);
     const int bpp = bytesPerPixel(AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
 
-    for (int width : { 7, 100, 275, 300 }) {
+    for (int32_t width : { 7, 100, 275, 300 }) {
         int result = AImageDecoder_setTargetSize(decoder, width, 100);
         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
 
@@ -706,8 +742,8 @@
 struct SampledSizeParams {
     AImageDecoder* decoder;
     int sampleSize;
-    int* width;
-    int* height;
+    int32_t* width;
+    int32_t* height;
 };
 
 static void testComputeSampledSize(JNIEnv* env, jclass, jlong imageDecoderPtr,
@@ -720,7 +756,7 @@
     const int32_t origWidth = AImageDecoderHeaderInfo_getWidth(info);
     const int32_t origHeight = AImageDecoderHeaderInfo_getHeight(info);
 
-    int width, height;
+    int32_t width, height;
     // Test some bad parameters.
     for (SampledSizeParams p : std::initializer_list<SampledSizeParams>{
         { nullptr, 2, &width, &height },
@@ -865,7 +901,7 @@
 
     const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
     const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
-    const AndroidBitmapFormat format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
+    const auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
     const size_t defaultStride = AImageDecoder_getMinimumStride(decoder);
 
     if (width == 1 && height == 1) {
@@ -930,7 +966,7 @@
     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
     ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
 
-    int newWidth = width / 2, newHeight = height / 2;
+    int32_t newWidth = width / 2, newHeight = height / 2;
     result = AImageDecoder_setTargetSize(decoder, newWidth, newHeight);
     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
     const size_t halfStride = AImageDecoder_getMinimumStride(decoder);
@@ -1182,7 +1218,7 @@
 static JNINativeMethod gMethods[] = {
     { "nTestEmptyCreate", "()V", (void*) testEmptyCreate },
     { "nTestNullDecoder", "(" ASSET_MANAGER STRING ")V", (void*) testNullDecoder },
-    { "nTestInfo", "(JII" STRING "ZZI)V", (void*) testInfo },
+    { "nTestInfo", "(JII" STRING "ZI)V", (void*) testInfo },
     { "nOpenAsset", "(" ASSET_MANAGER STRING ")J", (void*) openAssetNative },
     { "nCloseAsset", "(J)V", (void*) closeAsset },
     { "nCreateFromAsset", "(J)J", (void*) createFromAsset },
diff --git a/tests/tests/graphics/jni/android_graphics_cts_FrameRateCtsActivity.cpp b/tests/tests/graphics/jni/android_graphics_cts_FrameRateCtsActivity.cpp
new file mode 100644
index 0000000..1361e3d
--- /dev/null
+++ b/tests/tests/graphics/jni/android_graphics_cts_FrameRateCtsActivity.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 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.
+ *
+ */
+
+#define LOG_TAG "FrameRateCtsActivity"
+
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+#include <android/surface_control.h>
+#include <jni.h>
+
+#include <array>
+
+namespace {
+
+jint nativeWindowSetFrameRate(JNIEnv* env, jclass, jobject jSurface, jfloat frameRate) {
+    ANativeWindow* window = nullptr;
+    if (jSurface) {
+        window = ANativeWindow_fromSurface(env, jSurface);
+    }
+    return ANativeWindow_setFrameRate(window, frameRate);
+}
+
+jlong surfaceControlCreate(JNIEnv* env, jclass, jobject jParentSurface) {
+    ANativeWindow* window = nullptr;
+    if (jParentSurface) {
+        window = ANativeWindow_fromSurface(env, jParentSurface);
+    }
+    if (!window) {
+        return 0;
+    }
+    return reinterpret_cast<jlong>(
+            ASurfaceControl_createFromWindow(window, "SetFrameRateTestSurface"));
+}
+
+void surfaceControlDestroy(JNIEnv*, jclass, jlong surfaceControlLong) {
+    if (surfaceControlLong == 0) {
+        return;
+    }
+    ASurfaceControl* surfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControlLong);
+    ASurfaceTransaction* transaction = ASurfaceTransaction_create();
+    ASurfaceTransaction_reparent(transaction, surfaceControl, nullptr);
+    ASurfaceTransaction_apply(transaction);
+    ASurfaceTransaction_delete(transaction);
+    ASurfaceControl_release(surfaceControl);
+}
+
+void surfaceControlSetFrameRate(JNIEnv*, jclass, jlong surfaceControlLong, jfloat frameRate) {
+    ASurfaceControl* surfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControlLong);
+    ASurfaceTransaction* transaction = ASurfaceTransaction_create();
+    ASurfaceTransaction_setFrameRate(transaction, surfaceControl, frameRate);
+    ASurfaceTransaction_apply(transaction);
+    ASurfaceTransaction_delete(transaction);
+}
+
+const std::array<JNINativeMethod, 4> JNI_METHODS = {{
+        {"nativeWindowSetFrameRate", "(Landroid/view/Surface;F)I", (void*)nativeWindowSetFrameRate},
+        {"nativeSurfaceControlCreate", "(Landroid/view/Surface;)J", (void*)surfaceControlCreate},
+        {"nativeSurfaceControlDestroy", "(J)V", (void*)surfaceControlDestroy},
+        {"nativeSurfaceControlSetFrameRate", "(JF)V", (void*)surfaceControlSetFrameRate},
+}};
+
+} // namespace
+
+int register_android_graphics_cts_FrameRateCtsActivity(JNIEnv* env) {
+    jclass clazz = env->FindClass("android/graphics/cts/FrameRateCtsActivity");
+    return env->RegisterNatives(clazz, JNI_METHODS.data(), JNI_METHODS.size());
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/AImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/AImageDecoderTest.java
index bebed43..df11998 100644
--- a/tests/tests/graphics/src/android/graphics/cts/AImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/AImageDecoderTest.java
@@ -93,20 +93,20 @@
 
     // For testing all of the assets as premul and unpremul.
     private static Object[] getAssetRecordsUnpremul() {
-        return ImageDecoderTest.crossProduct(getAssetRecords(), new Object[] { true, false });
+        return Utils.crossProduct(getAssetRecords(), new Object[] { true, false });
     }
 
     private static Object[] getRecordsUnpremul() {
-        return ImageDecoderTest.crossProduct(getRecords(), new Object[] { true, false });
+        return Utils.crossProduct(getRecords(), new Object[] { true, false });
     }
 
     // For testing all of the assets at different sample sizes.
     private static Object[] getAssetRecordsSample() {
-        return ImageDecoderTest.crossProduct(getAssetRecords(), new Object[] { 2, 3, 4, 8, 16 });
+        return Utils.crossProduct(getAssetRecords(), new Object[] { 2, 3, 4, 8, 16 });
     }
 
     private static Object[] getRecordsSample() {
-        return ImageDecoderTest.crossProduct(getRecords(), new Object[] { 2, 3, 4, 8, 16 });
+        return Utils.crossProduct(getRecords(), new Object[] { 2, 3, 4, 8, 16 });
     }
 
     @Test
@@ -131,8 +131,7 @@
         long aimagedecoder = nCreateFromAssetBuffer(asset);
 
         nTestInfo(aimagedecoder, record.width, record.height, "image/png",
-                false /* isAnimated */, record.isF16,
-                nativeDataSpace(record.getColorSpace()));
+                record.isF16, nativeDataSpace(record.getColorSpace()));
         nCloseAsset(asset);
     }
 
@@ -145,8 +144,7 @@
         long aimagedecoder = nCreateFromAssetFd(asset);
 
         nTestInfo(aimagedecoder, record.width, record.height, "image/png",
-                false /* isAnimated */, record.isF16,
-                nativeDataSpace(record.getColorSpace()));
+                record.isF16, nativeDataSpace(record.getColorSpace()));
         nCloseAsset(asset);
     }
 
@@ -157,8 +155,7 @@
         long aimagedecoder = nCreateFromAsset(asset);
 
         nTestInfo(aimagedecoder, record.width, record.height, "image/png",
-                false /* isAnimated */, record.isF16,
-                nativeDataSpace(record.getColorSpace()));
+                record.isF16, nativeDataSpace(record.getColorSpace()));
         nCloseAsset(asset);
     }
 
@@ -183,8 +180,7 @@
             long aimagedecoder = nCreateFromFd(pfd.getFd());
 
             nTestInfo(aimagedecoder, record.width, record.height, record.mimeType,
-                    false /* isAnimated */, false /*isF16*/,
-                    nativeDataSpace(record.colorSpace));
+                    false /*isF16*/, nativeDataSpace(record.colorSpace));
         } catch (FileNotFoundException e) {
             fail("Could not open " + Utils.getAsResourceUri(record.resId));
         }
@@ -201,8 +197,7 @@
             long aimagedecoder = nCreateFromFd(pfd.getFd());
 
             nTestInfo(aimagedecoder, record.width, record.height, record.mimeType,
-                    false /* isAnimated */, false /*isF16*/,
-                    nativeDataSpace(record.colorSpace));
+                    false /*isF16*/, nativeDataSpace(record.colorSpace));
         } catch (FileNotFoundException e) {
             fail("Could not open " + Utils.getAsResourceUri(record.resId));
         } catch (ErrnoException err) {
@@ -920,7 +915,7 @@
     }
 
     private static Object[] rgbColorSpacesAndCompressFormats() {
-        return ImageDecoderTest.crossProduct(rgbColorSpaces(), Bitmap.CompressFormat.values());
+        return Utils.crossProduct(rgbColorSpaces(), Bitmap.CompressFormat.values());
     }
 
     String toMimeType(Bitmap.CompressFormat format) {
@@ -959,7 +954,7 @@
         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file,
                 ParcelFileDescriptor.MODE_READ_ONLY)) {
             long aimagedecoder = nCreateFromFd(pfd.getFd());
-            nTestInfo(aimagedecoder, width, height, toMimeType(format), false, false, dataSpace);
+            nTestInfo(aimagedecoder, width, height, toMimeType(format), false, dataSpace);
         } catch (IOException e) {
             e.printStackTrace();
             fail("Could not read " + file);
@@ -1023,7 +1018,7 @@
     // For convenience, all methods that take aimagedecoder as a parameter delete
     // it.
     private static native void nTestInfo(long aimagedecoder, int width, int height,
-            String mimeType, boolean isAnimated, boolean isF16, int dataspace);
+            String mimeType, boolean isF16, int dataspace);
     private static native void nTestSetFormat(long aimagedecoder, boolean isF16, boolean isGray);
     private static native void nTestSetUnpremul(long aimagedecoder, boolean hasAlpha);
     private static native void nTestGetMinimumStride(long aimagedecoder,
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
index 93d3d8d..5603b9d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
@@ -1038,22 +1038,37 @@
         assertTrue(pass);
     }
 
-    private Object[] compressFormats() {
-        return Bitmap.CompressFormat.values();
+    private Object[] compressFormatsAndColorSpaces() {
+        return Utils.crossProduct(Bitmap.CompressFormat.values(),
+                BitmapTest.getRgbColorSpaces().toArray());
     }
 
     @Test
-    @Parameters(method = "compressFormats")
-    public void testEncodeP3(Bitmap.CompressFormat format) {
+    @Parameters(method = "compressFormatsAndColorSpaces")
+    public void testEncodeColorSpace(Bitmap.CompressFormat format, ColorSpace colorSpace) {
         Bitmap b = null;
+        ColorSpace decodedColorSpace = null;
         ImageDecoder.Source src = ImageDecoder.createSource(mResources.getAssets(),
                 "blue-16bit-srgb.png");
         try {
             b = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                decoder.setTargetColorSpace(colorSpace);
             });
             assertNotNull(b);
             assertEquals(Bitmap.Config.RGBA_F16, b.getConfig());
+            decodedColorSpace = b.getColorSpace();
+
+            // Requesting a ColorSpace with an EXTENDED variant will use the EXTENDED one because
+            // the image is 16-bit.
+            if (colorSpace == ColorSpace.get(ColorSpace.Named.SRGB)) {
+                assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), decodedColorSpace);
+            } else if (colorSpace == ColorSpace.get(ColorSpace.Named.LINEAR_SRGB)) {
+                assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB),
+                          decodedColorSpace);
+            } else {
+                assertSame(colorSpace, decodedColorSpace);
+            }
         } catch (IOException e) {
             fail("Failed with " + e);
         }
@@ -1065,9 +1080,28 @@
         src = ImageDecoder.createSource(ByteBuffer.wrap(array));
 
         try {
-            Bitmap b2 = ImageDecoder.decodeBitmap(src);
-            assertEquals("Wrong color space for " + format,
-                    ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b2.getColorSpace());
+            Bitmap b2 = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+            ColorSpace encodedColorSpace = b2.getColorSpace();
+            if (format == Bitmap.CompressFormat.PNG) {
+                assertEquals(Bitmap.Config.RGBA_F16, b2.getConfig());
+                assertSame(decodedColorSpace, encodedColorSpace);
+            } else {
+                // Compressing to the other formats does not support creating a compressed version
+                // that we will decode to F16.
+                assertEquals(Bitmap.Config.ARGB_8888, b2.getConfig());
+
+                // Decoding an EXTENDED variant to 8888 results in the non-extended variant.
+                if (decodedColorSpace == ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)) {
+                    assertSame(ColorSpace.get(ColorSpace.Named.SRGB), encodedColorSpace);
+                } else if (decodedColorSpace
+                        == ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)) {
+                    assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB), encodedColorSpace);
+                } else {
+                    assertSame(decodedColorSpace, encodedColorSpace);
+                }
+            }
         } catch (IOException e) {
             fail("Failed with " + e);
         }
diff --git a/tests/tests/graphics/src/android/graphics/cts/FrameRateCtsActivity.java b/tests/tests/graphics/src/android/graphics/cts/FrameRateCtsActivity.java
new file mode 100644
index 0000000..37a91a4
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/FrameRateCtsActivity.java
@@ -0,0 +1,335 @@
+/*
+ * 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.
+ */
+
+package android.graphics.cts;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * An Activity to help with frame rate testing.
+ */
+public class FrameRateCtsActivity extends Activity {
+    static {
+        System.loadLibrary("ctsgraphics_jni");
+    }
+
+    private static String TAG = "FrameRateCtsActivity";
+    private static final long WAIT_FOR_SURFACE_TIMEOUT_SECONDS = 3;
+    private static final long FRAME_RATE_SWITCH_GRACE_PERIOD_SECONDS = 1;
+    private static final long STABLE_FRAME_RATE_WAIT_SECONDS = 1;
+
+    private DisplayManager mDisplayManager;
+    private SurfaceView mSurfaceView;
+    private Handler mHandler = new Handler(Looper.getMainLooper());
+    private Object mLock = new Object();
+    private Surface mSurface = null;
+    private float mDeviceFrameRate;
+    private ArrayList<Float> mFrameRateChangedEvents = new ArrayList<Float>();
+
+    SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            synchronized (mLock) {
+                mSurface = holder.getSurface();
+                mLock.notify();
+            }
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+            synchronized (mLock) {
+                mSurface = null;
+                mLock.notify();
+            }
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
+    };
+
+    DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
+        @Override
+        public void onDisplayAdded(int displayId) {}
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            if (displayId != Display.DEFAULT_DISPLAY) {
+                return;
+            }
+            synchronized (mLock) {
+                float frameRate = mDisplayManager.getDisplay(displayId).getMode().getRefreshRate();
+                if (frameRate != mDeviceFrameRate) {
+                    Log.i(TAG,
+                            String.format("Frame rate changed: %.0f --> %.0f", mDeviceFrameRate,
+                                    frameRate));
+                    mDeviceFrameRate = frameRate;
+                    mFrameRateChangedEvents.add(frameRate);
+                    mLock.notify();
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {}
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        synchronized (mLock) {
+            mDisplayManager = (DisplayManager) getSystemService(DISPLAY_SERVICE);
+            mDeviceFrameRate =
+                    mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getMode().getRefreshRate();
+            mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+            mSurfaceView = new SurfaceView(this);
+            mSurfaceView.setWillNotDraw(false);
+            mSurfaceView.setZOrderOnTop(true);
+            setContentView(mSurfaceView,
+                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT));
+            mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mDisplayManager.unregisterDisplayListener(mDisplayListener);
+    }
+
+    private ArrayList<Float> getFrameRatesToTest() {
+        Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        Display.Mode[] modes = display.getSupportedModes();
+        Display.Mode currentMode = display.getMode();
+        ArrayList<Float> frameRates = new ArrayList<Float>();
+        for (Display.Mode mode : modes) {
+            if (mode.getPhysicalWidth() == currentMode.getPhysicalWidth()
+                    && mode.getPhysicalHeight() == currentMode.getPhysicalHeight()) {
+                frameRates.add(mode.getRefreshRate());
+            }
+        }
+        Collections.sort(frameRates);
+        ArrayList<Float> uniqueFrameRates = new ArrayList<Float>();
+        for (float frameRate : frameRates) {
+            if (uniqueFrameRates.isEmpty()
+                    || frameRate - uniqueFrameRates.get(uniqueFrameRates.size() - 1) >= 1.0f) {
+                uniqueFrameRates.add(frameRate);
+            }
+        }
+        return uniqueFrameRates;
+    }
+
+    private void waitForSurface() throws InterruptedException {
+        if (mSurface == null) {
+            Log.i(TAG, "Waiting for surface");
+        }
+        long nowNanos = System.nanoTime();
+        long endTimeNanos = nowNanos + WAIT_FOR_SURFACE_TIMEOUT_SECONDS * 1_000_000_000L;
+        while (mSurface == null) {
+            long timeRemainingMillis = (endTimeNanos - nowNanos) / 1_000_000;
+            assertTrue("Never got a surface", timeRemainingMillis > 0);
+            mLock.wait(timeRemainingMillis);
+            nowNanos = System.nanoTime();
+        }
+    }
+
+    private boolean isDeviceFrameRateCompatibleWithAppRequest(
+            float deviceFrameRate, float appRequestedFrameRate) {
+        float multiple = deviceFrameRate / appRequestedFrameRate;
+        int roundedMultiple = Math.round(multiple);
+        return roundedMultiple > 0
+                && Math.abs(roundedMultiple * appRequestedFrameRate - deviceFrameRate) <= 0.1f;
+    }
+
+    private void postBuffer() {
+        Canvas canvas = mSurfaceView.getHolder().lockHardwareCanvas();
+        canvas.drawColor(Color.BLUE);
+        mSurfaceView.getHolder().unlockCanvasAndPost(canvas);
+    }
+
+    private void setFrameRateSurface(float frameRate) {
+        Log.i(TAG, String.format("Setting frame rate to %.0f", frameRate));
+        mSurface.setFrameRate(frameRate);
+        postBuffer();
+    }
+
+    private void setFrameRateANativeWindow(float frameRate) {
+        Log.i(TAG, String.format("Setting frame rate to %.0f", frameRate));
+        nativeWindowSetFrameRate(mSurface, frameRate);
+        postBuffer();
+    }
+
+    private void setFrameRateSurfaceControl(float frameRate) {
+        Log.i(TAG, String.format("Setting frame rate to %.0f", frameRate));
+        SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+        transaction.setFrameRate(mSurfaceView.getSurfaceControl(), frameRate).apply();
+        transaction.close();
+        postBuffer();
+    }
+
+    private void setFrameRateNativeSurfaceControl(long surfaceControl, float frameRate) {
+        Log.i(TAG, String.format("Setting frame rate to %.0f", frameRate));
+        nativeSurfaceControlSetFrameRate(surfaceControl, frameRate);
+    }
+
+    private void verifyCompatibleAndStableFrameRate(float appRequestedFrameRate)
+            throws InterruptedException {
+        Log.i(TAG, "Verifying compatible and stable frame rate");
+        long nowNanos = System.nanoTime();
+        long gracePeriodEndTimeNanos =
+                nowNanos + FRAME_RATE_SWITCH_GRACE_PERIOD_SECONDS * 1_000_000_000L;
+        while (true) {
+            // Wait until we switch to a compatible frame rate.
+            while (!isDeviceFrameRateCompatibleWithAppRequest(
+                           mDeviceFrameRate, appRequestedFrameRate)
+                    && gracePeriodEndTimeNanos > nowNanos) {
+                mLock.wait((gracePeriodEndTimeNanos - nowNanos) / 1_000_000);
+                nowNanos = System.nanoTime();
+                assertTrue("Lost the surface", mSurface != null);
+            }
+
+            // TODO(b/148033900): Remove the if and error log below, and replace it with this
+            // assertTrue() call, once we have a way to ignore display manager policy.
+            //
+            // assertTrue(
+            //         String.format(
+            //                 "Timed out waiting for a stable and compatible frame rate."
+            //                 + " requested=%.0f current=%.0f.",
+            //                 appRequestedFrameRate, mDeviceFrameRate),
+            //         gracePeriodEndTimeNanos > nowNanos);
+            if (nowNanos >= gracePeriodEndTimeNanos) {
+                Log.e(TAG,
+                        String.format(
+                                "Timed out waiting for a stable and compatible frame rate."
+                                + " requested=%.0f current=%.0f.",
+                                appRequestedFrameRate, mDeviceFrameRate));
+                return;
+            }
+
+            // We've switched to a compatible frame rate. Now wait for a while to see if we stay at
+            // that frame rate.
+            long endTimeNanos = nowNanos + STABLE_FRAME_RATE_WAIT_SECONDS * 1_000_000_000L;
+            while (endTimeNanos > nowNanos) {
+                mFrameRateChangedEvents.clear();
+                mLock.wait((endTimeNanos - nowNanos) / 1_000_000);
+                nowNanos = System.nanoTime();
+                assertTrue("Lost the surface", mSurface != null);
+                if (!mFrameRateChangedEvents.isEmpty()) {
+                    break;
+                }
+                if (nowNanos >= endTimeNanos) {
+                    Log.i(TAG, String.format("Stable frame rate %.0f verified", mDeviceFrameRate));
+                    return;
+                }
+            }
+        }
+    }
+
+    public void testSurfaceSetFrameRate() throws InterruptedException {
+        ArrayList<Float> frameRatesToTest = getFrameRatesToTest();
+        Log.i(TAG, "Testing Surface.setFrameRate()");
+        synchronized (mLock) {
+            waitForSurface();
+            for (float frameRate : frameRatesToTest) {
+                setFrameRateSurface(frameRate);
+                verifyCompatibleAndStableFrameRate(frameRate);
+            }
+            setFrameRateSurface(-100.f);
+            Thread.sleep(1000);
+            setFrameRateSurface(0.f);
+        }
+        Log.i(TAG, "Done testing Surface.setFrameRate()");
+    }
+
+    public void testANativeWindowSetFrameRate() throws InterruptedException {
+        ArrayList<Float> frameRatesToTest = getFrameRatesToTest();
+        Log.i(TAG, "Testing ANativeWindow_setFrameRate()");
+        synchronized (mLock) {
+            waitForSurface();
+            for (float frameRate : frameRatesToTest) {
+                setFrameRateANativeWindow(frameRate);
+                verifyCompatibleAndStableFrameRate(frameRate);
+            }
+            setFrameRateANativeWindow(-100.f);
+            Thread.sleep(1000);
+            setFrameRateANativeWindow(0.f);
+        }
+        Log.i(TAG, "Done testing ANativeWindow_setFrameRate()");
+    }
+
+    public void testSurfaceControlSetFrameRate() throws InterruptedException {
+        ArrayList<Float> frameRatesToTest = getFrameRatesToTest();
+        Log.i(TAG, "Testing SurfaceControl.Transaction.setFrameRate()");
+        synchronized (mLock) {
+            waitForSurface();
+            for (float frameRate : frameRatesToTest) {
+                setFrameRateSurfaceControl(frameRate);
+                verifyCompatibleAndStableFrameRate(frameRate);
+            }
+            setFrameRateSurfaceControl(-100.f);
+            Thread.sleep(1000);
+            setFrameRateSurfaceControl(0.f);
+        }
+        Log.i(TAG, "Done testing SurfaceControl.Transaction.setFrameRate()");
+    }
+
+    public void testNativeSurfaceControlSetFrameRate() throws InterruptedException {
+        ArrayList<Float> frameRatesToTest = getFrameRatesToTest();
+        Log.i(TAG, "Testing ASurfaceTransaction_setFrameRate()");
+        long nativeSurfaceControl = 0;
+        try {
+            synchronized (mLock) {
+                waitForSurface();
+                nativeSurfaceControl = nativeSurfaceControlCreate(mSurface);
+                assertTrue("Failed to create a native SurfaceControl", nativeSurfaceControl != 0);
+                for (float frameRate : frameRatesToTest) {
+                    setFrameRateNativeSurfaceControl(nativeSurfaceControl, frameRate);
+                    verifyCompatibleAndStableFrameRate(frameRate);
+                }
+                setFrameRateNativeSurfaceControl(nativeSurfaceControl, -100.f);
+                Thread.sleep(1000);
+                setFrameRateNativeSurfaceControl(nativeSurfaceControl, 0.f);
+            }
+        } finally {
+            nativeSurfaceControlDestroy(nativeSurfaceControl);
+        }
+        Log.i(TAG, "Done testing ASurfaceTransaction_setFrameRate()");
+    }
+
+    private static native int nativeWindowSetFrameRate(Surface surface, float frameRate);
+    private static native long nativeSurfaceControlCreate(Surface parentSurface);
+    private static native void nativeSurfaceControlDestroy(long surfaceControl);
+    private static native void nativeSurfaceControlSetFrameRate(
+            long surfaceControl, float frameRate);
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index c5a8221..687e316 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -2480,25 +2480,10 @@
         }
     }
 
-
-    static Object[] crossProduct(Object[] a, Object[] b) {
-        final int length = a.length * b.length;
-        Object[] ret = new Object[length];
-        for (int i = 0; i < a.length; i++) {
-            for (int j = 0; j < b.length; j++) {
-                int index = i * b.length + j;
-                assertNull(ret[index]);
-                ret[index] = new Object[] { a[i], b[j] };
-            }
-        }
-        return ret;
-    }
-
     private Object[] getRecordsAsSources() {
-        return crossProduct(getRecords(), mCreators);
+        return Utils.crossProduct(getRecords(), mCreators);
     }
 
-
     @Test
     @LargeTest
     @Parameters(method = "getRecordsAsSources")
@@ -2530,7 +2515,7 @@
     }
 
     private Object[] getRecordsAsUris() {
-        return crossProduct(getRecords(), mUriCreators);
+        return Utils.crossProduct(getRecords(), mUriCreators);
     }
 
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java b/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java
new file mode 100644
index 0000000..65dcfcd
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.graphics.cts;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SetFrameRateTest {
+    @Rule
+    public ActivityTestRule<FrameRateCtsActivity> mActivityRule =
+            new ActivityTestRule<>(FrameRateCtsActivity.class);
+
+    @Test
+    public void testSetFrameRate() throws InterruptedException {
+        FrameRateCtsActivity activity = mActivityRule.getActivity();
+        activity.testSurfaceSetFrameRate();
+        activity.testANativeWindowSetFrameRate();
+        activity.testSurfaceControlSetFrameRate();
+        activity.testNativeSurfaceControlSetFrameRate();
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/Utils.java b/tests/tests/graphics/src/android/graphics/cts/Utils.java
index f7229ed..85b5b40 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Utils.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Utils.java
@@ -16,6 +16,7 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -112,4 +113,20 @@
         }
         return file;
     }
+
+    /**
+     * Helper for JUnit-Params tests to combine inputs.
+     */
+    static Object[] crossProduct(Object[] a, Object[] b) {
+        final int length = a.length * b.length;
+        Object[] ret = new Object[length];
+        for (int i = 0; i < a.length; i++) {
+            for (int j = 0; j < b.length; j++) {
+                int index = i * b.length + j;
+                assertNull(ret[index]);
+                ret[index] = new Object[] { a[i], b[j] };
+            }
+        }
+        return ret;
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/lights/cts/LightsManagerTest.java b/tests/tests/hardware/src/android/hardware/lights/cts/LightsManagerTest.java
new file mode 100755
index 0000000..a30ca46
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/lights/cts/LightsManagerTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.lights.cts.tests;
+
+import static android.hardware.lights.LightsRequest.Builder;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsManager;
+
+import androidx.annotation.ColorInt;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LightsManagerTest {
+
+    private static final @ColorInt int TAN = 0xffd2b48c;
+    private static final @ColorInt int RED = 0xffff0000;
+
+    private LightsManager mManager;
+    private List<Light> mLights;
+
+    @Before
+    public void setUp() {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(
+                        android.Manifest.permission.CONTROL_DEVICE_LIGHTS);
+
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mManager = context.getSystemService(LightsManager.class);
+        mLights = mManager.getLights();
+    }
+
+    @After
+    public void tearDown() {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testControlLightsPermissionIsRequiredToUseLights() {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+        try {
+            mManager.getLights();
+            fail("Expected SecurityException to be thrown for getLights()");
+        } catch (SecurityException expected) {
+        }
+
+        try (LightsManager.LightsSession session = mManager.openSession()) {
+            fail("Expected SecurityException to be thrown for openSession()");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testControlSingleLight() {
+        assumeTrue(mLights.size() >= 1);
+
+        try (LightsManager.LightsSession session = mManager.openSession()) {
+            // When the session requests to turn a single light on:
+            session.setLights(new Builder()
+                    .setLight(mLights.get(0), new LightState(RED))
+                    .build());
+
+            // Then the light should turn on.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(RED);
+        }
+    }
+
+    @Test
+    public void testControlMultipleLights() {
+        assumeTrue(mLights.size() >= 2);
+
+        try (LightsManager.LightsSession session = mManager.openSession()) {
+            // When the session requests to turn two of the lights on:
+            session.setLights(new Builder()
+                    .setLight(mLights.get(0), new LightState(0xffaaaaff))
+                    .setLight(mLights.get(1), new LightState(0xffbbbbff))
+                    .build());
+
+            // Then both should turn on.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(0xffaaaaff);
+            assertThat(mManager.getLightState(mLights.get(1)).getColor()).isEqualTo(0xffbbbbff);
+
+            // Any others should remain off.
+            for (int i = 2; i < mLights.size(); i++) {
+                assertThat(mManager.getLightState(mLights.get(i)).getColor()).isEqualTo(0x00);
+            }
+        }
+    }
+
+    @Test
+    public void testControlLights_onlyEffectiveForLifetimeOfClient() {
+        assumeTrue(mLights.size() >= 1);
+
+        // The light should begin by being off.
+        assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(0x00);
+
+        try (LightsManager.LightsSession session = mManager.openSession()) {
+            // When a session commits changes:
+            session.setLights(new Builder().setLight(mLights.get(0), new LightState(TAN)).build());
+            // Then the light should turn on.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(TAN);
+
+            // When the session goes away:
+            session.close();
+            // Then the light should turn off.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(0x00);
+        }
+    }
+
+    @Test
+    public void testControlLights_firstCallerWinsContention() {
+        assumeTrue(mLights.size() >= 1);
+
+        try (LightsManager.LightsSession session1 = mManager.openSession();
+                LightsManager.LightsSession session2 = mManager.openSession()) {
+
+            // When session1 and session2 both request the same light:
+            session1.setLights(new Builder().setLight(mLights.get(0), new LightState(TAN)).build());
+            session2.setLights(new Builder().setLight(mLights.get(0), new LightState(RED)).build());
+            // Then session1 should win because it was created first.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(TAN);
+
+            // When session1 goes away:
+            session1.close();
+            // Then session2 should have its request go into effect.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(RED);
+
+            // When session2 goes away:
+            session2.close();
+            // Then the light should turn off because there are no more sessions.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(0);
+        }
+    }
+
+    @Test
+    public void testClearLight() {
+        assumeTrue(mLights.size() >= 1);
+
+        try (LightsManager.LightsSession session = mManager.openSession()) {
+            // When the session turns a light on:
+            session.setLights(new Builder().setLight(mLights.get(0), new LightState(RED)).build());
+            // And then the session clears it again:
+            session.setLights(new Builder().clearLight(mLights.get(0)).build());
+            // Then the light should turn back off.
+            assertThat(mManager.getLightState(mLights.get(0)).getColor()).isEqualTo(0);
+        }
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 0847800..55fecfe 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -885,9 +885,9 @@
         assertNotNull(rootOfTrust.getVerifiedBootKey());
         assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
                    " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
-        checkEntropy(rootOfTrust.getVerifiedBootKey());
         if (requireLocked) {
             assertTrue(rootOfTrust.isDeviceLocked());
+            checkEntropy(rootOfTrust.getVerifiedBootKey());
             assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
         }
     }
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
index 6db5494..11b0c62 100644
--- a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -744,7 +744,7 @@
                     !gListenerGotValidExpiryTime ||
                     !gOnKeyChangeListenerOK) && count++ < 5) {
                // Prevents race condition when the event arrives late
-               usleep(2000);
+               usleep(10000);
             }
 
             if (!gGotVendorDefinedEvent) {
diff --git a/tests/tests/media/res/raw/id3test0.mp3 b/tests/tests/media/res/raw/id3test0.mp3
new file mode 100644
index 0000000..5730b6b
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test0.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test1.mp3 b/tests/tests/media/res/raw/id3test1.mp3
new file mode 100644
index 0000000..af52e0f
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test1.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test10.mp3 b/tests/tests/media/res/raw/id3test10.mp3
new file mode 100644
index 0000000..ac01a00
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test10.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test11.mp3 b/tests/tests/media/res/raw/id3test11.mp3
new file mode 100644
index 0000000..5786b80
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test11.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test2.mp3 b/tests/tests/media/res/raw/id3test2.mp3
new file mode 100644
index 0000000..7fdb737
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test3.mp3 b/tests/tests/media/res/raw/id3test3.mp3
new file mode 100644
index 0000000..a9ce936
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test4.mp3 b/tests/tests/media/res/raw/id3test4.mp3
new file mode 100644
index 0000000..f2d2df9
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test4.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test5.mp3 b/tests/tests/media/res/raw/id3test5.mp3
new file mode 100644
index 0000000..4ee1200
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test5.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test6.mp3 b/tests/tests/media/res/raw/id3test6.mp3
new file mode 100644
index 0000000..017e0c0
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test6.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test7.mp3 b/tests/tests/media/res/raw/id3test7.mp3
new file mode 100644
index 0000000..d106a46
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test7.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test8.mp3 b/tests/tests/media/res/raw/id3test8.mp3
new file mode 100644
index 0000000..ab83c86
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test8.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/id3test9.mp3 b/tests/tests/media/res/raw/id3test9.mp3
new file mode 100644
index 0000000..84d2c49
--- /dev/null
+++ b/tests/tests/media/res/raw/id3test9.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/programstream.mpeg b/tests/tests/media/res/raw/programstream.mpeg
new file mode 100644
index 0000000..6f8a480
--- /dev/null
+++ b/tests/tests/media/res/raw/programstream.mpeg
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index f967b3e..75ea6da 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -23,6 +23,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.graphics.ImageFormat;
+import android.hardware.display.DisplayManager;
 import android.media.cts.CodecUtils;
 import android.media.Image;
 import android.media.AudioFormat;
@@ -36,6 +37,7 @@
 import android.media.MediaFormat;
 import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
+import android.view.Display;
 import android.view.Surface;
 import android.net.Uri;
 
@@ -89,6 +91,7 @@
     private static final String VIDEO_URL_KEY = "decoder_test_video_url";
     private static final String MODULE_NAME = "CtsMediaTestCases";
     private DynamicConfigDeviceSide dynamicConfig;
+    private DisplayManager mDisplayManager;
 
     @Override
     protected void setUp() throws Exception {
@@ -114,6 +117,7 @@
         masterFd.close();
 
         dynamicConfig = new DynamicConfigDeviceSide(MODULE_NAME);
+        mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
     }
 
     @Override
@@ -924,7 +928,12 @@
             }
             String[] decoderNames = MediaUtils.getDecoderNames(format);
 
-            if (decoderNames == null || decoderNames.length == 0) {
+            int numberOfSupportedHdrTypes =
+                    mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getHdrCapabilities()
+                            .getSupportedHdrTypes().length;
+
+            if (decoderNames == null || decoderNames.length == 0
+                    || numberOfSupportedHdrTypes == 0) {
                 MediaUtils.skipTest("No video codecs supports HDR");
                 return;
             }
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 21149c6..01a39bf 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -23,6 +23,7 @@
 import android.icu.util.ULocale;
 import android.media.AudioFormat;
 import android.media.AudioPresentation;
+import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaDataSource;
 import android.media.MediaExtractor;
@@ -784,6 +785,75 @@
         assertTrue("could not read alac mov", totalSize > 0);
     }
 
+    public void testProgramStreamExtraction() throws Exception {
+        AssetFileDescriptor testFd = mResources.openRawResourceFd(R.raw.programstream);
+
+        MediaExtractor extractor = new MediaExtractor();
+        extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
+                testFd.getLength());
+        testFd.close();
+        assertEquals("There must be 2 tracks", 2, extractor.getTrackCount());
+        extractor.selectTrack(0);
+        extractor.selectTrack(1);
+        boolean lastAdvanceResult = true;
+        boolean lastReadResult = true;
+        int [] bytesRead = new int[2];
+        MediaCodec [] codecs = { null, null };
+
+        try {
+            MediaFormat f = extractor.getTrackFormat(0);
+            codecs[0] = MediaCodec.createDecoderByType(f.getString(MediaFormat.KEY_MIME));
+            codecs[0].configure(f, null /* surface */, null /* crypto */, 0 /* flags */);
+            codecs[0].start();
+        } catch (IOException | IllegalArgumentException e) {
+            // ignore
+        }
+        try {
+            MediaFormat f = extractor.getTrackFormat(1);
+            codecs[1] = MediaCodec.createDecoderByType(f.getString(MediaFormat.KEY_MIME));
+            codecs[1].configure(f, null /* surface */, null /* crypto */, 0 /* flags */);
+            codecs[1].start();
+        } catch (IOException | IllegalArgumentException e) {
+            // ignore
+        }
+
+        ByteBuffer buf = ByteBuffer.allocate(2*1024*1024);
+        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+        while(true) {
+            for (MediaCodec codec : codecs) {
+                if (codec != null) {
+                    int idx = codec.dequeueOutputBuffer(info, 5);
+                    if (idx >= 0) {
+                        codec.releaseOutputBuffer(idx, false);
+                    }
+                }
+            }
+            int trackIdx = extractor.getSampleTrackIndex();
+            MediaCodec codec = codecs[trackIdx];
+            ByteBuffer b = buf;
+            int bufIdx = -1;
+            if (codec != null) {
+                bufIdx = codec.dequeueInputBuffer(-1);
+                b = codec.getInputBuffer(bufIdx);
+            }
+            int n = extractor.readSampleData(b, 0);
+            if (n > 0) {
+                bytesRead[trackIdx] += n;
+            }
+            if (codec != null) {
+                int sampleFlags = extractor.getSampleFlags();
+                long sampleTime = extractor.getSampleTime();
+                codec.queueInputBuffer(bufIdx, 0, n, sampleTime, sampleFlags);
+            }
+            if (!extractor.advance()) {
+                break;
+            }
+        }
+        assertTrue("did not read from track 0", bytesRead[0] > 0);
+        assertTrue("did not read from track 1", bytesRead[1] > 0);
+        extractor.release();
+    }
+
     private void doTestAdvance(int res) throws Exception {
         AssetFileDescriptor testFd = mResources.openRawResourceFd(res);
 
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
index 9066c1b..ffe7a1f 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
@@ -323,6 +323,29 @@
                 mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER));
     }
 
+    public void testGenreParsing() {
+        Object [][] genres = {
+            { R.raw.id3test0, null },
+            { R.raw.id3test1, "Country" },
+            { R.raw.id3test2, "Classic Rock, Android" },
+            { R.raw.id3test3, null },
+            { R.raw.id3test4, "Classic Rock, (Android)" },
+            { R.raw.id3test5, null },
+            { R.raw.id3test6, "Funk, Grunge, Hip-Hop" },
+            { R.raw.id3test7, null },
+            { R.raw.id3test8, "Disco" },
+            { R.raw.id3test9, "Cover" },
+            { R.raw.id3test10, "Pop, Remix" },
+            { R.raw.id3test11, "Remix" },
+        };
+        for (Object [] genre: genres) {
+            setDataSourceFd((Integer)genre[0] /* resource id */);
+            assertEquals("Unexpected genre: ",
+                    genre[1] /* genre */,
+                    mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
+        }
+    }
+
     public void testBitsPerSampleAndSampleRate() {
         setDataSourceFd(R.raw.testwav_16bit_44100hz);
 
diff --git a/tests/tests/nativemedia/mediametrics/src/MediaMetricsTest.cpp b/tests/tests/nativemedia/mediametrics/src/MediaMetricsTest.cpp
index fef80ba..4267da7 100644
--- a/tests/tests/nativemedia/mediametrics/src/MediaMetricsTest.cpp
+++ b/tests/tests/nativemedia/mediametrics/src/MediaMetricsTest.cpp
@@ -19,7 +19,7 @@
 
 #include <gtest/gtest.h>
 #include <utils/Log.h>
-#include <MediaMetrics.h>
+#include <media/MediaMetrics.h>
 
 //-----------------------------------------------------------------
 class MediaMetricsTest : public ::testing::Test {
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
index f872b5c..6e87253 100644
--- a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
@@ -35,6 +35,7 @@
 import android.app.UiAutomation;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.service.notification.Condition;
@@ -62,6 +63,8 @@
     private NotificationManager mNm;
     private ActivityManager mActivityManager;
     private Context mContext;
+    private ZenModeBroadcastReceiver mModeReceiver;
+    private IntentFilter mModeFilter;
     private ArraySet<String> ids = new ArraySet<>();
 
     @Before
@@ -77,10 +80,15 @@
         mNm = (NotificationManager) mContext.getSystemService(
                 Context.NOTIFICATION_SERVICE);
         mNm.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+        mModeReceiver = new ZenModeBroadcastReceiver();
+        mModeFilter = new IntentFilter();
+        mModeFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
+        mContext.registerReceiver(mModeReceiver, mModeFilter);
     }
 
     @After
     public void tearDown() throws Exception {
+        mContext.unregisterReceiver(mModeReceiver);
         if (mNm == null) {
             // assumption in setUp is false, so mNm is not initialized
             return;
@@ -115,8 +123,12 @@
         final ComponentName cn = SecondaryConditionProviderService.getId();
 
         // add rule
+        mModeReceiver.reset();
+
         addRule(cn, INTERRUPTION_FILTER_ALARMS, true);
         pollForSubscribe(SecondaryConditionProviderService.getInstance());
+
+        mModeReceiver.waitFor(1/*Secondary only*/, 1000/*Limit is 1 second*/);
         assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
 
         // unbind service
@@ -143,11 +155,15 @@
         pollForConnection(SecondaryConditionProviderService.class, true);
 
         // add rules for both
+        mModeReceiver.reset();
+
         addRule(LegacyConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, true);
         pollForSubscribe(LegacyConditionProviderService.getInstance());
 
         addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_ALARMS, true);
         pollForSubscribe(SecondaryConditionProviderService.getInstance());
+
+        mModeReceiver.waitFor(2/*Legacy and Secondary*/, 1000/*Limit is 1 second*/);
         assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
 
         // unbind one of the services
@@ -175,11 +191,15 @@
         pollForConnection(SecondaryConditionProviderService.class, true);
 
         // add rules for both
+        mModeReceiver.reset();
+
         addRule(LegacyConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, true);
         pollForSubscribe(LegacyConditionProviderService.getInstance());
 
         addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_ALARMS, true);
         pollForSubscribe(SecondaryConditionProviderService.getInstance());
+
+        mModeReceiver.waitFor(2/*Legacy and Secondary*/, 1000/*Limit is 1 second*/);
         assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
 
         // unbind one of the services
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ZenModeBroadcastReceiver.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ZenModeBroadcastReceiver.java
new file mode 100644
index 0000000..7c735e5
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ZenModeBroadcastReceiver.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+package android.app.notification.legacy.cts;
+
+import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
+import static java.lang.Thread.sleep;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+public class ZenModeBroadcastReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent.getAction() == null ||
+            intent.getPackage() == null) {
+            return;
+        }
+
+        if (intent.getAction().equals(ACTION_INTERRUPTION_FILTER_CHANGED) &&
+            intent.getPackage().equals(InstrumentationRegistry.getContext().getPackageName())) {
+            mCount++;
+        }
+    }
+
+    public void reset() {
+        mCount = 0;
+        mReset = true;
+    }
+
+    public void waitFor(int count, int ms) throws IllegalStateException {
+        if (!mReset) {
+            throw new IllegalStateException("Call reset() before waitFor()!");
+        }
+        mReset = false;
+
+        final int delayMs = 100;
+        while (ms > 0 && mCount < count) {
+            ms -= delayMs;
+            try {
+                sleep(delayMs);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        Log.d(TAG, "Exit from wait due to " +
+                (mCount < count ? "timeout" : "intents") + ".");
+    }
+
+    private static String TAG = "CpsTest";
+    private int mCount = 0;
+    private boolean mReset = true;
+}
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
index a8a8917..c6af7c8 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
@@ -21,13 +21,20 @@
 import android.content.Intent
 import android.net.Uri
 import android.platform.test.annotations.AppModeFull
+
 import androidx.test.InstrumentationRegistry
 import androidx.test.runner.AndroidJUnit4
+
 import com.android.compatibility.common.util.AppOpsUtils
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+
+import org.junit.After
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+
 import java.util.concurrent.TimeUnit
 
 private const val INSTALL_BUTTON_ID = "button1"
@@ -38,11 +45,22 @@
 class IntentTest : PackageInstallerTestBase() {
     private val context = InstrumentationRegistry.getTargetContext()
 
+    private fun setSecureFrp(secureFrp: Boolean) {
+        runWithShellPermissionIdentity {
+            runShellCommand("settings put secure secure_frp_mode ${if (secureFrp) 1 else 0}")
+        }
+    }
+
     @Before
     fun allowToInstallPackages() {
         AppOpsUtils.setOpMode(context.packageName, APP_OP_STR, MODE_ALLOWED)
     }
 
+    @After
+    fun disableSecureFrp() {
+        setSecureFrp(false)
+    }
+
     /**
      * Check that we can install an app via a package-installer intent
      */
@@ -92,4 +110,22 @@
         assertEquals(RESULT_OK, reinstall.get(TIMEOUT, TimeUnit.MILLISECONDS))
         assertInstalled()
     }
+
+    /**
+     * Check that we can't install an app via a package-installer intent if Secure FRP is enabled
+     */
+    @Test
+    fun packageNotInstalledSecureFrp() {
+        setSecureFrp(true)
+        try {
+            val installation = startInstallationViaIntent()
+            clickInstallerUIButton(INSTALL_BUTTON_ID)
+
+            // Install should not have succeeded
+            assertEquals(RESULT_CANCELED, installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
+            assertNotInstalled()
+        } finally {
+            setSecureFrp(false)
+        }
+    }
 }
diff --git a/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java b/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
index 8609e33..84c2dd6 100644
--- a/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
+++ b/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
@@ -25,11 +25,15 @@
 import static android.content.Context.WIFI_P2P_SERVICE;
 import static android.content.Context.WIFI_SERVICE;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 
+import android.app.WallpaperManager;
 import android.content.Context;
 import android.platform.test.annotations.AppModeInstant;
 
+import com.android.compatibility.common.util.RequiredServiceRule;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -68,8 +72,14 @@
 
     @Test
     public void cannotGetWallpaperManager() {
-        assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
-                WALLPAPER_SERVICE));
+        WallpaperManager mgr  = (WallpaperManager) InstrumentationRegistry.getTargetContext()
+                .getSystemService(WALLPAPER_SERVICE);
+        boolean supported = RequiredServiceRule.hasService("wallpaper");
+        if (supported) {
+            assertNull(mgr);
+        } else {
+            assertFalse(mgr.isWallpaperSupported());
+        }
     }
 
     @Test
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 7a7fa44..904beef 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -1462,6 +1462,13 @@
         android:protectionLevel="signature|privileged" />
     <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
 
+    <!-- @SystemApi Allows an application to use the Context Hub.
+         <p>Not for use by third-party applications.
+         @hide
+    -->
+    <permission android:name="android.permission.ACCESS_CONTEXT_HUB"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to create mock location providers for testing.
          <p>Protection level: signature
          @hide
@@ -2637,6 +2644,11 @@
     <permission android:name="android.permission.READ_DEVICE_CONFIG"
         android:protectionLevel="signature|preinstalled" />
 
+    <!-- @SystemApi @hide Allows an application to monitor access to config settings.
+    <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"
+                android:protectionLevel="signature" />
+
     <!-- @SystemApi @TestApi Allows an application to call
         {@link android.app.ActivityManager#forceStopPackage}.
         @hide -->
@@ -3238,6 +3250,13 @@
     <permission android:name="android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by an {@link android.service.autofill.InlineSuggestionRenderService}
+         to ensure that only the system can bind to it.
+         @hide This is not a third-party API (intended for OEMs and system apps).
+    -->
+    <permission android:name="android.permission.BIND_INLINE_SUGGESTION_RENDER_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a android.service.textclassifier.TextClassifierService,
          to ensure that only the system can bind to it.
          @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
@@ -4200,6 +4219,11 @@
     <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
         android:protectionLevel="signature" />
 
+    <!-- Allows applications to set the initial lockscreen state.
+         <p>Not for use by third-party applications. @hide -->
+    <permission android:name="android.permission.SET_INITIAL_LOCK"
+        android:protectionLevel="signature|setup"/>
+
     <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
     <permission android:name="android.permission.MANAGE_FINGERPRINT"
         android:protectionLevel="signature|privileged" />
diff --git a/tests/tests/rcs/AndroidManifest.xml b/tests/tests/rcs/AndroidManifest.xml
deleted file mode 100755
index 15a4038..0000000
--- a/tests/tests/rcs/AndroidManifest.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2018 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.telephony.ims.cts"
-    android:targetSandboxVersion="2">
-
-    <uses-permission android:name="android.permission.READ_SMS" />
-    <uses-permission android:name="android.permission.SEND_SMS" />
-    <uses-permission android:name="android.permission.RECEIVE_SMS" />
-    <uses-permission android:name="android.permission.RECEIVE_MMS" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-
-        <!-- Required to be default SMS app -->
-        <receiver android:name="android.telephony.ims.SmsApplicationSmsDeliverReceiver"
-                  android:permission="android.permission.BROADCAST_SMS">
-
-            <intent-filter>
-                <action android:name="android.provider.Telephony.SMS_DELIVER" />
-            </intent-filter>
-
-        </receiver>
-
-        <!-- Required to be default SMS app -->
-        <receiver android:name="android.telephony.ims.SmsApplicationWapPushDeliverReceiver"
-                  android:permission="android.permission.BROADCAST_WAP_PUSH">
-
-            <intent-filter>
-                <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
-                <data android:mimeType="application/vnd.wap.mms-message" />
-            </intent-filter>
-
-        </receiver>
-
-        <!-- Required to be default SMS app -->
-        <service android:name="android.telephony.ims.SmsApplicationService"
-                 android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
-                 android:exported="true" >
-            <intent-filter>
-                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="sms" />
-                <data android:scheme="smsto" />
-                <data android:scheme="mms" />
-                <data android:scheme="mmsto" />
-            </intent-filter>
-        </service>
-
-        <!-- Required to be default SMS app -->
-        <activity
-            android:name="android.telephony.ims.SmsApplicationActivity"
-            android:label="RCS CTS Test Application Activity"
-            android:windowSoftInputMode="stateHidden">
-
-            <intent-filter>
-                <action android:name="android.intent.action.SEND" />
-                <action android:name="android.intent.action.SENDTO" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.BROWSABLE" />
-                <data android:scheme="sms" />
-                <data android:scheme="smsto" />
-                <data android:scheme="mms" />
-                <data android:scheme="mmsto" />
-            </intent-filter>
-        </activity>
-
-    </application>
-
-    <!--  self-instrumenting test package. -->
-    <instrumentation
-        android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:label="RCS CTS tests"
-        android:targetPackage="android.telephony.ims.cts" >
-    </instrumentation>
-</manifest>
-
diff --git a/tests/tests/rcs/OWNERS b/tests/tests/rcs/OWNERS
deleted file mode 100644
index f901c4f..0000000
--- a/tests/tests/rcs/OWNERS
+++ /dev/null
@@ -1,16 +0,0 @@
-amitmahajan@google.com
-breadley@google.com
-fionaxu@google.com
-hallliu@google.com
-jackyu@google.com
-jminjie@google.com
-lelandmiller@google.com
-mpq@google.com
-nazaninb@google.com
-paulye@google.com
-refuhoo@google.com
-rgreenwalt@google.com
-sahinc@google.com
-satk@google.com
-shuoq@google.com
-tgunn@google.com
\ No newline at end of file
diff --git a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationActivity.java b/tests/tests/rcs/src/android/telephony/ims/SmsApplicationActivity.java
deleted file mode 100644
index 3588046..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationActivity.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony.ims;
-
-import android.app.Activity;
-
-/**
- * This activity is used to provide the interface required for a default SMS application. It
- * intentionally has no custom behavior.
- */
-public class SmsApplicationActivity extends Activity {}
-
diff --git a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationService.java b/tests/tests/rcs/src/android/telephony/ims/SmsApplicationService.java
deleted file mode 100644
index 302228e..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony.ims;
-
-import android.app.IntentService;
-import android.content.Intent;
-
-/**
- * This service is used to provide the interface required for a default SMS application. It
- * intentionally has no custom behavior.
- */
-public class SmsApplicationService extends IntentService {
-    private static final String TAG = "SmsApplicationService";
-
-    public SmsApplicationService() {
-        super(TAG);
-    }
-
-    @Override
-    protected void onHandleIntent(Intent intent) {
-        // Do nothing
-    }
-}
diff --git a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationSmsDeliverReceiver.java b/tests/tests/rcs/src/android/telephony/ims/SmsApplicationSmsDeliverReceiver.java
deleted file mode 100644
index 8bcc9bc..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationSmsDeliverReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony.ims;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * This receiver is used to provide the interface required for a default SMS application. It
- * intentionally has no custom behavior.
- */
-public class SmsApplicationSmsDeliverReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // Do nothing
-    }
-}
diff --git a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationWapPushDeliverReceiver.java b/tests/tests/rcs/src/android/telephony/ims/SmsApplicationWapPushDeliverReceiver.java
deleted file mode 100644
index 5f6ea5b..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/SmsApplicationWapPushDeliverReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony.ims;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * This receiver is used to provide the interface required for a default SMS application. It
- * intentionally has no custom behavior.
- */
-public class SmsApplicationWapPushDeliverReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // Do nothing
-    }
-}
diff --git a/tests/tests/rcs/src/android/telephony/ims/cts/DefaultSmsAppHelper.java b/tests/tests/rcs/src/android/telephony/ims/cts/DefaultSmsAppHelper.java
deleted file mode 100644
index a26cd05..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/cts/DefaultSmsAppHelper.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony.ims.cts;
-
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
-
-import androidx.test.InstrumentationRegistry;
-
-class DefaultSmsAppHelper {
-    static void ensureDefaultSmsApp() {
-        String packageName =
-                InstrumentationRegistry.getInstrumentation().getContext().getPackageName();
-        runShellCommand(
-                String.format("settings put secure sms_default_application %s", packageName));
-    }
-}
diff --git a/tests/tests/rcs/src/android/telephony/ims/cts/Rcs1To1ThreadTest.java b/tests/tests/rcs/src/android/telephony/ims/cts/Rcs1To1ThreadTest.java
deleted file mode 100644
index 516a5bb..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/cts/Rcs1To1ThreadTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.
- */
-package android.telephony.ims.cts;
-
-import static android.provider.Telephony.RcsColumns.IS_RCS_TABLE_SCHEMA_CODE_COMPLETE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.telephony.ims.Rcs1To1Thread;
-import android.telephony.ims.RcsMessageManager;
-import android.telephony.ims.RcsMessageStoreException;
-import android.telephony.ims.RcsParticipant;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.AfterClass;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class Rcs1To1ThreadTest {
-    private RcsMessageManager mRcsMessageManager;
-    private Context mContext;
-
-    @BeforeClass
-    public static void ensureDefaultSmsApp() {
-        DefaultSmsAppHelper.ensureDefaultSmsApp();
-    }
-
-    @Before
-    public void setupTestEnvironment() {
-        // Used to skip tests for production builds without RCS tables, will be removed when
-        // IS_RCS_TABLE_SCHEMA_CODE_COMPLETE flag is removed.
-        Assume.assumeTrue(IS_RCS_TABLE_SCHEMA_CODE_COMPLETE);
-
-        mContext = InstrumentationRegistry.getTargetContext();
-        mRcsMessageManager = mContext.getSystemService(RcsMessageManager.class);
-
-        cleanup();
-    }
-
-    @AfterClass
-    public static void cleanup() {
-        // TODO(b/123997749) should clean RCS message store here
-    }
-
-    @Test
-    public void testRcs1To1Thread_isGroupReturnsFalse() throws RcsMessageStoreException {
-        RcsParticipant participant = mRcsMessageManager.createRcsParticipant(
-                "+1234567890", "Alice");
-        Rcs1To1Thread thread = mRcsMessageManager.createRcs1To1Thread(participant);
-
-        assertThat(thread.isGroup()).isFalse();
-    }
-
-    @Test
-    public void testRcs1To1Thread_fallbackThreadIdCanBeSet() throws RcsMessageStoreException {
-        RcsParticipant participant = mRcsMessageManager.createRcsParticipant(
-                "+1234567890", "Alice");
-        Rcs1To1Thread thread = mRcsMessageManager.createRcs1To1Thread(participant);
-
-        thread.setFallbackThreadId(2);
-
-        assertThat(thread.getFallbackThreadId()).isEqualTo(2);
-    }
-}
diff --git a/tests/tests/rcs/src/android/telephony/ims/cts/RcsEventTest.java b/tests/tests/rcs/src/android/telephony/ims/cts/RcsEventTest.java
deleted file mode 100644
index c6ed244..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/cts/RcsEventTest.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony.ims.cts;
-
-import static android.provider.Telephony.RcsColumns.IS_RCS_TABLE_SCHEMA_CODE_COMPLETE;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.content.Context;
-import android.net.Uri;
-import android.telephony.ims.RcsEvent;
-import android.telephony.ims.RcsEventQueryParams;
-import android.telephony.ims.RcsEventQueryResult;
-import android.telephony.ims.RcsGroupThread;
-import android.telephony.ims.RcsGroupThreadEvent;
-import android.telephony.ims.RcsGroupThreadIconChangedEvent;
-import android.telephony.ims.RcsGroupThreadNameChangedEvent;
-import android.telephony.ims.RcsGroupThreadParticipantJoinedEvent;
-import android.telephony.ims.RcsGroupThreadParticipantLeftEvent;
-import android.telephony.ims.RcsMessageManager;
-import android.telephony.ims.RcsMessageStoreException;
-import android.telephony.ims.RcsParticipant;
-import android.telephony.ims.RcsParticipantAliasChangedEvent;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.google.android.collect.Lists;
-
-import org.junit.AfterClass;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.util.function.Predicate;
-
-public class RcsEventTest {
-    private RcsMessageManager mRcsMessageManager;
-
-    private long mTimestamp;
-    private RcsParticipant mParticipant1;
-    private RcsParticipant mParticipant2;
-    private RcsGroupThread mGroupThread;
-
-    @BeforeClass
-    public static void ensureDefaultSmsApp() {
-        DefaultSmsAppHelper.ensureDefaultSmsApp();
-    }
-
-
-    @Before
-    public void setupTestEnvironment() throws RcsMessageStoreException {
-        // Used to skip tests for production builds without RCS tables, will be removed when
-        // IS_RCS_TABLE_SCHEMA_CODE_COMPLETE flag is removed.
-        Assume.assumeTrue(IS_RCS_TABLE_SCHEMA_CODE_COMPLETE);
-
-        Context context = InstrumentationRegistry.getTargetContext();
-        mRcsMessageManager = context.getSystemService(RcsMessageManager.class);
-
-        cleanup();
-
-        mTimestamp = 1234567890;
-        mParticipant1 = mRcsMessageManager.createRcsParticipant("403", "p1");
-        mParticipant2 = mRcsMessageManager.createRcsParticipant("404", "p2");
-        mGroupThread = mRcsMessageManager.createGroupThread(
-                Lists.newArrayList(mParticipant1, mParticipant2), "groupName", Uri.EMPTY);
-
-    }
-
-    @AfterClass
-    public static void cleanup() {
-        // TODO(b/123997749) should clean RCS message store here
-    }
-
-    @Test
-    public void testCreateRcsEvent_canSaveAndQueryGroupThreadParticipantJoinedEvent()
-            throws RcsMessageStoreException {
-        RcsGroupThreadParticipantJoinedEvent rcsGroupThreadParticipantJoinedEvent =
-                new RcsGroupThreadParticipantJoinedEvent(
-                        mTimestamp, mGroupThread, mParticipant1, mParticipant2);
-
-        mRcsMessageManager.persistRcsEvent(rcsGroupThreadParticipantJoinedEvent);
-
-        assertMatchingEventInQuery(
-                RcsEventQueryParams.GROUP_THREAD_PARTICIPANT_JOINED_EVENT,
-                event -> matches(rcsGroupThreadParticipantJoinedEvent, event));
-    }
-
-    @Test
-    public void testCreateRcsEvent_canSaveAndQueryGroupThreadNameChangedEvent()
-            throws RcsMessageStoreException {
-        RcsGroupThreadNameChangedEvent rcsGroupThreadNameChangedEvent =
-                new RcsGroupThreadNameChangedEvent(
-                        mTimestamp, mGroupThread, mParticipant1, "newName");
-
-        mRcsMessageManager.persistRcsEvent(rcsGroupThreadNameChangedEvent);
-
-        assertMatchingEventInQuery(
-                RcsEventQueryParams.GROUP_THREAD_NAME_CHANGED_EVENT,
-                event -> matches(rcsGroupThreadNameChangedEvent, event));
-    }
-
-    @Test
-    public void testCreateRcsEvent_canSaveAndQueryParticipantAliasChangedEvent()
-            throws RcsMessageStoreException {
-        RcsParticipantAliasChangedEvent rcsParticipantAliasChangedEvent
-                = new RcsParticipantAliasChangedEvent(mTimestamp, mParticipant1, "newAlias");
-
-        mRcsMessageManager.persistRcsEvent(rcsParticipantAliasChangedEvent);
-
-        assertMatchingEventInQuery(
-                RcsEventQueryParams.PARTICIPANT_ALIAS_CHANGED_EVENT,
-                event -> matches(rcsParticipantAliasChangedEvent, event));
-    }
-
-    @Test
-    public void testCreateRcsEvent_canSaveAndQueryGroupThreadParticipantLeftEvent()
-            throws RcsMessageStoreException {
-        RcsGroupThreadParticipantLeftEvent rcsGroupThreadParticipantLeftEvent =
-                new RcsGroupThreadParticipantLeftEvent(
-                        mTimestamp, mGroupThread, mParticipant1, mParticipant2);
-
-        mRcsMessageManager.persistRcsEvent(rcsGroupThreadParticipantLeftEvent);
-
-        assertMatchingEventInQuery(
-                RcsEventQueryParams.GROUP_THREAD_PARTICIPANT_LEFT_EVENT,
-                event -> matches(rcsGroupThreadParticipantLeftEvent, event));
-    }
-
-    @Test
-    public void testCreateRcsEvent_canSaveAndQueryGroupThreadIconChangedEvent()
-            throws RcsMessageStoreException {
-        Uri newIcon = Uri.parse("cool/new/icon");
-
-        RcsGroupThreadIconChangedEvent rcsGroupThreadIconChangedEvent =
-                new RcsGroupThreadIconChangedEvent(
-                        mTimestamp, mGroupThread, mParticipant1, newIcon);
-
-        mRcsMessageManager.persistRcsEvent(rcsGroupThreadIconChangedEvent);
-
-        assertMatchingEventInQuery(
-                RcsEventQueryParams.GROUP_THREAD_ICON_CHANGED_EVENT,
-                event -> matches(rcsGroupThreadIconChangedEvent, event));
-    }
-
-    private void assertMatchingEventInQuery(int queryMessageType, Predicate<RcsEvent> predicate)
-            throws RcsMessageStoreException {
-        RcsEventQueryResult queryResult = mRcsMessageManager.getRcsEvents(
-                new RcsEventQueryParams.Builder()
-                        .setEventType(queryMessageType)
-                        .build());
-
-        boolean foundMatch = queryResult.getEvents().stream().anyMatch(predicate);
-
-        assertWithMessage(queryResult.getEvents().toString()).that(foundMatch).isTrue();
-    }
-
-    private boolean matches(RcsGroupThreadParticipantJoinedEvent expected, RcsEvent actual) {
-        if (!(actual instanceof RcsGroupThreadParticipantJoinedEvent)) {
-            return false;
-        }
-        RcsGroupThreadParticipantJoinedEvent actualParticipantJoinedEvent =
-                (RcsGroupThreadParticipantJoinedEvent) actual;
-
-        return matchesGroupThreadEvent(expected, actualParticipantJoinedEvent)
-                && actualParticipantJoinedEvent.getJoinedParticipant().getId()
-                        == expected.getJoinedParticipant().getId();
-    }
-
-
-    private boolean matches(RcsGroupThreadNameChangedEvent expected, RcsEvent actual) {
-        if (!(actual instanceof RcsGroupThreadNameChangedEvent)) {
-            return false;
-        }
-        RcsGroupThreadNameChangedEvent actualGroupThreadNameChangedEvent =
-                (RcsGroupThreadNameChangedEvent) actual;
-
-        return matchesGroupThreadEvent(expected, actualGroupThreadNameChangedEvent)
-                && actualGroupThreadNameChangedEvent.getNewName().equals(expected.getNewName());
-    }
-
-    private boolean matches(RcsGroupThreadParticipantLeftEvent expected, RcsEvent actual) {
-        if (!(actual instanceof RcsGroupThreadParticipantLeftEvent)) {
-            return false;
-        }
-        RcsGroupThreadParticipantLeftEvent actualParticipantLeftEvent =
-                (RcsGroupThreadParticipantLeftEvent) actual;
-
-        return matchesGroupThreadEvent(expected, actualParticipantLeftEvent)
-                && actualParticipantLeftEvent.getLeavingParticipant().getId()
-                        == expected.getLeavingParticipant().getId();
-    }
-
-
-    private boolean matches(RcsGroupThreadIconChangedEvent expected, RcsEvent actual) {
-        if (!(actual instanceof RcsGroupThreadIconChangedEvent)) {
-            return false;
-        }
-        RcsGroupThreadIconChangedEvent actualIconChangedEvent =
-                (RcsGroupThreadIconChangedEvent) actual;
-
-        return matchesGroupThreadEvent(expected, actualIconChangedEvent)
-                && actualIconChangedEvent.getNewIcon().equals(expected.getNewIcon());
-    }
-
-    private boolean matchesGroupThreadEvent(
-            RcsGroupThreadEvent expected, RcsGroupThreadEvent actual) {
-        return matchesRcsEventFields(expected, actual)
-                && actual.getOriginatingParticipant().getId()
-                        == expected.getOriginatingParticipant().getId()
-                && actual.getRcsGroupThread().getThreadId()
-                        == expected.getRcsGroupThread().getThreadId();
-    }
-
-    private boolean matches(RcsParticipantAliasChangedEvent expected, RcsEvent actual) {
-        if (!(actual instanceof RcsParticipantAliasChangedEvent)) {
-            return false;
-        }
-        RcsParticipantAliasChangedEvent actualIconChangedEvent =
-                (RcsParticipantAliasChangedEvent) actual;
-
-        return matchesRcsEventFields(expected, actual)
-                && actualIconChangedEvent.getParticipant().getId()
-                        == expected.getParticipant().getId()
-                && actualIconChangedEvent.getNewAlias().equals(expected.getNewAlias());
-    }
-
-    private boolean matchesRcsEventFields(RcsEvent expected, RcsEvent actual) {
-        return actual.getTimestamp() == expected.getTimestamp();
-    }
-}
diff --git a/tests/tests/rcs/src/android/telephony/ims/cts/RcsParticipantTest.java b/tests/tests/rcs/src/android/telephony/ims/cts/RcsParticipantTest.java
deleted file mode 100644
index 7da8e63..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/cts/RcsParticipantTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony.ims.cts;
-
-import static android.provider.Telephony.RcsColumns.IS_RCS_TABLE_SCHEMA_CODE_COMPLETE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.telephony.ims.RcsMessageManager;
-import android.telephony.ims.RcsMessageStoreException;
-import android.telephony.ims.RcsParticipant;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.AfterClass;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class RcsParticipantTest {
-    RcsMessageManager mRcsMessageManager;
-    Context mContext;
-
-    @BeforeClass
-    public static void ensureDefaultSmsApp() {
-        DefaultSmsAppHelper.ensureDefaultSmsApp();
-    }
-
-    @Before
-    public void setupTestEnvironment() {
-        // Used to skip tests for production builds without RCS tables, will be removed when
-        // IS_RCS_TABLE_SCHEMA_CODE_COMPLETE flag is removed.
-        Assume.assumeTrue(IS_RCS_TABLE_SCHEMA_CODE_COMPLETE);
-
-        mContext = InstrumentationRegistry.getTargetContext();
-        mRcsMessageManager = mContext.getSystemService(RcsMessageManager.class);
-
-        cleanup();
-    }
-
-    @AfterClass
-    public static void cleanup() {
-        // TODO(b/123997749) should clean RCS message store here
-    }
-
-    @Test
-    public void testCreateRcsParticipant_returnsValidParticipant() throws RcsMessageStoreException {
-        String expectedCanonicalAddress = "+12223334444";
-        String expectedAlias = "test_alias";
-
-        createAndValidateParticipant(expectedCanonicalAddress, expectedAlias);
-    }
-
-    @Test
-    public void testCreateRcsParticipant_shouldNotCrashForExistingCanonicalAddress()
-            throws RcsMessageStoreException {
-        String expectedCanonicalAddress = "+12223334444";
-        String expectedAlias1 = "test_alias_1";
-        String expectedAlias2 = "test_alias_2";
-
-        createAndValidateParticipant(expectedCanonicalAddress, expectedAlias1);
-        createAndValidateParticipant(expectedCanonicalAddress, expectedAlias2);
-    }
-
-    private void createAndValidateParticipant(String expectedCanonicalAddress,
-            String expectedAlias) throws RcsMessageStoreException {
-        RcsParticipant rcsParticipant =
-                mRcsMessageManager.createRcsParticipant(expectedCanonicalAddress, expectedAlias);
-
-        assertThat(rcsParticipant).isNotNull();
-        assertThat(rcsParticipant.getId()).isGreaterThan(0);
-        assertThat(rcsParticipant.getAlias()).isEqualTo(expectedAlias);
-    }
-}
diff --git a/tests/tests/rcs/src/android/telephony/ims/cts/RcsProviderPermissionsTest.java b/tests/tests/rcs/src/android/telephony/ims/cts/RcsProviderPermissionsTest.java
deleted file mode 100644
index c1e0af0..0000000
--- a/tests/tests/rcs/src/android/telephony/ims/cts/RcsProviderPermissionsTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-package android.telephony.ims.cts;
-
-import static android.provider.Telephony.RcsColumns.IS_RCS_TABLE_SCHEMA_CODE_COMPLETE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.ContentProviderClient;
-import android.content.Context;
-import android.provider.Telephony;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class RcsProviderPermissionsTest {
-    @BeforeClass
-    public static void ensureDefaultSmsApp() {
-        DefaultSmsAppHelper.ensureDefaultSmsApp();
-    }
-
-    @Before
-    public void setupTestEnvironment() {
-        // Used to skip tests for production builds without RCS tables, will be removed when
-        // IS_RCS_TABLE_SCHEMA_CODE_COMPLETE flag is removed.
-        Assume.assumeTrue(IS_RCS_TABLE_SCHEMA_CODE_COMPLETE);
-    }
-
-    @Test
-    public void testRcsProvider_shouldNotHaveAccess() {
-        Context context = InstrumentationRegistry.getTargetContext();
-
-        try (ContentProviderClient client =
-                     context.getContentResolver().acquireContentProviderClient(
-                             Telephony.RcsColumns.AUTHORITY)) {
-            assertThat(client).isNull();
-        } catch (SecurityException e) {
-            return;
-        }
-        Assert.fail();
-    }
-}
diff --git a/tests/tests/security/res/raw/sig_com_google_android_tzdata2.bin b/tests/tests/security/res/raw/sig_com_google_android_tzdata2.bin
new file mode 100644
index 0000000..95b0e10
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_tzdata2.bin
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/CertificateData.java b/tests/tests/security/src/android/security/cts/CertificateData.java
index ef27222..0b4780f 100644
--- a/tests/tests/security/src/android/security/cts/CertificateData.java
+++ b/tests/tests/security/src/android/security/cts/CertificateData.java
@@ -33,14 +33,12 @@
       "92:5A:8F:8D:2C:6D:04:E0:66:5F:59:6A:FF:22:D8:63:E8:25:6F:3F",
       "75:E0:AB:B6:13:85:12:27:1C:04:F8:5F:DD:DE:38:E4:B7:24:2E:FE",
       "DA:C9:02:4F:54:D8:F6:DF:94:93:5F:B1:73:26:38:CA:6A:D7:7C:13",
-      "74:20:74:41:72:9C:DD:92:EC:79:31:D8:23:10:8D:C2:81:92:E2:BB",
       "F4:8B:11:BF:DE:AB:BE:94:54:20:71:E6:41:DE:6B:BE:88:2B:40:B9",
       "58:E8:AB:B0:36:15:33:FB:80:F7:9B:1B:6D:29:D3:FF:8D:5F:00:F0",
       "55:A6:72:3E:CB:F2:EC:CD:C3:23:74:70:19:9D:2A:BE:11:E3:81:D1",
       "D6:9B:56:11:48:F0:1C:77:C5:45:78:C1:09:26:DF:5B:85:69:76:AD",
       "78:6A:74:AC:76:AB:14:7F:9C:6A:30:50:BA:9E:A8:7E:FE:9A:CE:3C",
       "09:3C:61:F3:8B:8B:DC:7D:55:DF:75:38:02:05:00:E1:25:F5:C8:36",
-      "8E:1C:74:F8:A6:20:B9:E5:8A:F4:61:FA:EC:2B:47:56:51:1A:52:C6",
       "27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4",
       "AD:7E:1C:28:B0:64:EF:8F:60:03:40:20:14:C3:D0:E3:37:0E:B5:8A",
       "8D:17:84:D5:37:F3:03:7D:EC:70:FE:57:8B:51:9A:99:E6:10:D7:B0",
@@ -67,11 +65,9 @@
       "8C:F4:27:FD:79:0C:3A:D1:66:06:8D:E8:1E:57:EF:BB:93:22:72:D4",
       "2F:78:3D:25:52:18:A7:4A:65:39:71:B5:2C:A2:9C:45:15:6F:E9:19",
       "BA:29:41:60:77:98:3F:F4:F3:EF:F2:31:05:3B:2E:EA:6D:4D:45:FD",
-      "85:A4:08:C0:9C:19:3E:5D:51:58:7D:CD:D6:13:30:FD:8C:DE:37:BF",
       "9B:AA:E5:9F:56:EE:21:CB:43:5A:BE:25:93:DF:A7:F0:40:D1:1D:CB",
       "36:79:CA:35:66:87:72:30:4D:30:A5:FB:87:3B:0F:A7:7B:B7:0D:54",
       "1B:8E:EA:57:96:29:1A:C9:39:EA:B8:0A:81:1A:73:73:C0:93:79:67",
-      "6E:26:64:F3:56:BF:34:55:BF:D1:93:3F:7C:01:DE:D8:13:DA:8A:A6",
       "74:3A:F0:52:9B:D0:32:A0:F4:4A:83:CD:D4:BA:A9:7B:7C:2E:C4:9A",
       "D8:EB:6B:41:51:92:59:E0:F3:E7:85:00:C0:3D:B6:88:97:C9:EE:FC",
       "66:31:BF:9E:F7:4F:9E:B6:C9:D5:A6:0C:BA:6A:BE:D1:F7:BD:EF:7B",
@@ -97,6 +93,7 @@
       "49:0A:75:74:DE:87:0A:47:FE:58:EE:F6:C7:6B:EB:C6:0B:12:40:99",
       "B5:1C:06:7C:EE:2B:0C:3D:F8:55:AB:2D:92:F4:FE:39:D4:E7:0F:0E",
       "29:36:21:02:8B:20:ED:02:F5:66:C5:32:D1:D6:ED:90:9F:45:00:2F",
+      "B6:AF:43:C2:9B:81:53:7D:F6:EF:6B:C3:1F:1F:60:15:0C:EE:48:66",
       "37:9A:19:7B:41:85:45:35:0C:A6:03:69:F3:3C:2E:AF:47:4F:20:79",
       "FA:B7:EE:36:97:26:62:FB:2D:B0:2A:F6:BF:03:FD:E8:7C:4B:2F:9B",
       "C3:19:7C:39:24:E6:54:AF:1B:C4:AB:20:95:7A:E2:C3:0E:13:02:6A",
@@ -124,10 +121,12 @@
       "9C:BB:48:53:F6:A4:F6:D3:52:A4:E8:32:52:55:60:13:F5:AD:AF:65",
       "B1:BC:96:8B:D4:F4:9D:62:2A:A8:9A:81:F2:15:01:52:A4:1D:82:9C",
       "20:D8:06:40:DF:9B:25:F5:12:25:3A:11:EA:F7:59:8A:EB:14:B5:47",
+      "30:43:FA:4F:F2:57:DC:A0:C3:80:EE:2E:58:EA:78:B2:3F:E6:BB:C1",
       "CF:9E:87:6D:D3:EB:FC:42:26:97:A3:B5:A3:7A:A0:76:A9:06:23:48",
       "2B:B1:F5:3E:55:0C:1D:C5:F1:D4:E6:B7:6A:46:4B:55:06:02:AC:21",
       "EC:50:35:07:B2:15:C4:95:62:19:E2:A8:9A:5B:42:99:2C:4C:2C:20",
       "47:BE:AB:C9:22:EA:E8:0E:78:78:34:62:A7:9F:45:C2:54:FD:E6:8B",
+      "58:A2:D0:EC:20:52:81:5B:C1:F3:F8:64:02:24:4E:C2:8E:02:4B:02",
       "3A:44:73:5A:E5:81:90:1F:24:86:61:46:1E:3B:9C:C4:5F:F5:3A:1B",
       "B3:1E:B1:B7:40:E3:6C:84:02:DA:DC:37:D4:4D:F5:D4:67:49:52:F9",
       "58:D1:DF:95:95:67:6B:63:C0:F0:5B:1C:17:4D:8B:84:0B:C8:78:BD",
@@ -148,11 +147,10 @@
       "F6:10:84:07:D6:F8:BB:67:98:0C:C2:E2:44:C2:EB:AE:1C:EF:63:BE",
       "AF:E5:D2:44:A8:D1:19:42:30:FF:47:9F:E2:F8:97:BB:CD:7A:8C:B4",
       "5F:3B:8C:F2:F8:10:B3:7D:78:B4:CE:EC:19:19:C3:73:34:B9:C7:74",
-      "9D:70:BB:01:A5:A4:A0:18:11:2E:F7:1C:01:B9:32:C5:34:E7:88:A8",
       "96:C9:1B:0B:95:B4:10:98:42:FA:D0:D8:22:79:FE:60:FA:B9:16:83",
-      "4F:65:8E:1F:E9:06:D8:28:02:E9:54:47:41:C9:54:25:5D:69:CC:1A",
       "A3:A1:B0:6F:24:61:23:4A:E3:36:A5:C2:37:FC:A6:FF:DD:F0:D7:3A",
       "D8:A6:33:2C:E0:03:6F:B1:85:F6:63:4F:7D:6A:06:65:26:32:28:27",
+      "E7:2E:F1:DF:FC:B2:09:28:CF:5D:D4:D5:67:37:B1:51:CB:86:4F:01",
       "01:0C:06:95:A6:98:19:14:FF:BF:5F:C6:B0:B6:95:EA:29:E9:12:A6",
       "0F:F9:40:76:18:D3:D7:6A:4B:98:F0:A8:35:9E:0C:FD:27:AC:CC:ED",
       "48:12:BD:92:3C:A8:C4:39:06:E7:30:6D:27:96:E6:A4:CF:22:2E:7D",
@@ -161,6 +159,8 @@
       "89:DF:74:FE:5C:F4:0F:4A:80:F9:E3:37:7D:54:DA:91:E1:01:31:8E",
       "7E:04:DE:89:6A:3E:66:6D:00:E6:87:D3:3F:FA:D9:3B:E8:3D:34:9E",
       "E1:C9:50:E6:EF:22:F8:4C:56:45:72:8B:92:20:60:D7:D5:A7:A3:E8",
+      "14:88:4E:86:26:37:B0:26:AF:59:62:5C:40:77:EC:35:29:BA:96:01",
+      "8A:C7:AD:8F:73:AC:4E:C1:B5:75:4D:A5:40:F4:FC:CF:7C:B5:8E:8C",
       "4E:B6:D5:78:49:9B:1C:CF:5F:58:1E:AD:56:BE:3D:9B:67:44:A5:E5",
       "5A:8C:EF:45:D7:A6:98:59:76:7A:8C:8B:44:96:B5:78:CF:47:4B:1A",
       "8D:A7:F9:65:EC:5E:FC:37:91:0F:1C:6E:59:FD:C1:CC:6A:6E:DE:16",
diff --git a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
index b621491..e7ab8eb 100644
--- a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
@@ -130,7 +130,7 @@
             ActivityInfo info = intent.resolveActivityInfo(
                     mContext.getPackageManager(), intent.getFlags());
             // Will throw NullPointerException if activity not found.
-            if (info.exported) {
+            if (info != null && info.exported) {
                 mContext.startActivity(intent);
             } else {
                 Log.i(TAG, "Activity is not exported");
diff --git a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
index 283910bf..3aec394 100644
--- a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
@@ -70,6 +70,14 @@
                 badPackages.isEmpty());
     }
 
+    /**
+     * Returns the well-known dev-key signatures, e.g. to detect cases where devices under test are
+     * using modules that have been signed using dev keys; Google will supply modules that have been
+     * signed with production keys in all cases.
+     *
+     * <p>See {@link #writeSignature(String, String)} for instructions for how to create the raw
+     * .bin files when adding entries to this list.
+     */
     private Set<Signature> getWellKnownSignatures() throws NotFoundException, IOException {
         Set<Signature> wellKnownSignatures = new HashSet<Signature>();
         wellKnownSignatures.add(getSignature(R.raw.sig_media));
@@ -95,6 +103,9 @@
         wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_resolv));
         wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_runtime_debug));
         wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_runtime_release));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_tzdata2));
+        // The following keys are no longer in use by modules, but it won't negatively affect tests
+        // to include their signatures here too.
         wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_tzdata));
         return wellKnownSignatures;
     }
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 10cd943..8185462 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -455,6 +455,56 @@
         assertConnectionState(connection, Connection.STATE_DISCONNECTED);
     }
 
+    public void testRejectIncomingCallWithUnwantedReason() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
+        final MockConnection connection = verifyConnectionForIncomingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+
+        final Call call = inCallService.getLastCall();
+
+        assertCallState(call, Call.STATE_RINGING);
+        assertConnectionState(connection, Connection.STATE_RINGING);
+
+        call.reject(Call.REJECT_REASON_UNWANTED);
+
+        assertCallState(call, Call.STATE_DISCONNECTED);
+        assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+        // The mock connection just stashes the reject reason in the disconnect cause string reason
+        // for tracking purposes.
+        assertEquals(Integer.toString(Call.REJECT_REASON_UNWANTED),
+                connection.getDisconnectCause().getReason());
+    }
+
+    public void testRejectIncomingCallWithDeclinedReason() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
+        final MockConnection connection = verifyConnectionForIncomingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+
+        final Call call = inCallService.getLastCall();
+
+        assertCallState(call, Call.STATE_RINGING);
+        assertConnectionState(connection, Connection.STATE_RINGING);
+
+        call.reject(Call.REJECT_REASON_DECLINED);
+
+        assertCallState(call, Call.STATE_DISCONNECTED);
+        assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+        // The mock connection just stashes the reject reason in the disconnect cause string reason
+        // for tracking purposes.
+        assertEquals(Integer.toString(Call.REJECT_REASON_DECLINED),
+                connection.getDisconnectCause().getReason());
+    }
+
     public void testRejectIncomingCallWithMessage() {
         if (!mShouldTestTelecom) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index 1704db9..463eb40 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -82,6 +82,14 @@
     }
 
     @Override
+    public void onReject(int rejectReason) {
+        super.onReject(rejectReason);
+        setDisconnected(new DisconnectCause(DisconnectCause.REJECTED,
+                Integer.toString(rejectReason)));
+        destroy();
+    }
+
+    @Override
     public void onReject(String reason) {
         super.onReject();
         setDisconnected(new DisconnectCause(DisconnectCause.REJECTED, reason));
diff --git a/tests/tests/telephony/current/AndroidTest.xml b/tests/tests/telephony/current/AndroidTest.xml
index 326b336..99aa5cb 100644
--- a/tests/tests/telephony/current/AndroidTest.xml
+++ b/tests/tests/telephony/current/AndroidTest.xml
@@ -34,6 +34,7 @@
         <option name="test-file-name" value="TestSmsRetrieverApp.apk"/>
         <option name="test-file-name" value="TestFinancialSmsApp.apk"/>
         <option name="test-file-name" value="LocationAccessingApp.apk"/>
+        <option name="test-file-name" value="LocationAccessingAppSdk28.apk"/>
         <option name="test-file-name" value="TestExternalImsServiceApp.apk"/>
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/tests/telephony/current/LocationAccessingApp/Android.bp b/tests/tests/telephony/current/LocationAccessingApp/Android.bp
index 5604c75..da9ffce 100644
--- a/tests/tests/telephony/current/LocationAccessingApp/Android.bp
+++ b/tests/tests/telephony/current/LocationAccessingApp/Android.bp
@@ -2,8 +2,7 @@
     name: "LocationAccessingApp",
     defaults: ["cts_defaults"],
     srcs: [
-        "src/**/*.java",
-        "aidl/**/I*.aidl",
+        ":location_accessing_app_srcs",
     ],
     aidl: {
         local_include_dirs: ["aidl/"],
@@ -15,3 +14,11 @@
         "mts",
     ],
 }
+
+filegroup {
+    name: "location_accessing_app_srcs",
+    srcs: [
+        "src/**/*.java",
+        "aidl/**/I*.aidl",
+    ],
+}
\ No newline at end of file
diff --git a/tests/tests/telephony/current/LocationAccessingApp/sdk28/Android.bp b/tests/tests/telephony/current/LocationAccessingApp/sdk28/Android.bp
new file mode 100644
index 0000000..ed6d2a6
--- /dev/null
+++ b/tests/tests/telephony/current/LocationAccessingApp/sdk28/Android.bp
@@ -0,0 +1,13 @@
+android_test {
+    name: "LocationAccessingAppSdk28",
+    defaults: ["cts_defaults"],
+    srcs: [
+        ":location_accessing_app_srcs",
+    ],
+    sdk_version: "test_current",
+    test_suites: [
+        "cts",
+        "vts",
+        "mts",
+    ],
+}
diff --git a/tests/tests/telephony/current/LocationAccessingApp/sdk28/AndroidManifest.xml b/tests/tests/telephony/current/LocationAccessingApp/sdk28/AndroidManifest.xml
new file mode 100644
index 0000000..811d9ce
--- /dev/null
+++ b/tests/tests/telephony/current/LocationAccessingApp/sdk28/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?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.telephony.cts.locationaccessingapp.sdk28">
+
+  <uses-sdk android:targetSdkVersion="28"/>
+  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+  <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+
+  <application android:label="LocationAccessingAppSdk28">
+    <service android:name="android.telephony.cts.locationaccessingapp.CtsLocationAccessService"
+             android:launchMode="singleInstance">
+      <intent-filter>
+        <action android:name="android.telephony.cts.locationaccessingapp.ACTION_CONTROL" />
+      </intent-filter>
+    </service>
+  </application>
+</manifest>
+
diff --git a/tests/tests/telephony/current/LocationAccessingApp/src/android/telephony/cts/locationaccessingapp/CtsLocationAccessService.java b/tests/tests/telephony/current/LocationAccessingApp/src/android/telephony/cts/locationaccessingapp/CtsLocationAccessService.java
index fa9608a..861de55 100644
--- a/tests/tests/telephony/current/LocationAccessingApp/src/android/telephony/cts/locationaccessingapp/CtsLocationAccessService.java
+++ b/tests/tests/telephony/current/LocationAccessingApp/src/android/telephony/cts/locationaccessingapp/CtsLocationAccessService.java
@@ -18,6 +18,7 @@
 
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -27,6 +28,8 @@
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+import android.telephony.cdma.CdmaCellLocation;
+import android.telephony.gsm.GsmCellLocation;
 
 import java.util.Collections;
 import java.util.List;
@@ -60,7 +63,17 @@
                     result = mTelephonyManager.getAllCellInfo();
                     break;
                 case COMMAND_GET_CELL_LOCATION:
-                    result = mTelephonyManager.getCellLocation();
+                    result = new Bundle();
+                    CellLocation cellLocation = mTelephonyManager.getCellLocation();
+                    if (cellLocation instanceof GsmCellLocation) {
+                        ((GsmCellLocation) cellLocation).fillInNotifierBundle((Bundle) result);
+                    } else if (cellLocation instanceof CdmaCellLocation) {
+                        ((CdmaCellLocation) cellLocation).fillInNotifierBundle((Bundle) result);
+                    } else if (cellLocation == null) {
+                        result = null;
+                    } else {
+                        throw new RuntimeException("Unexpected celllocation type");
+                    }
                     break;
                 case COMMAND_GET_SERVICE_STATE_FROM_LISTENER:
                     result = listenForServiceState();
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
index e8bd95c..2529ada 100644
--- a/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
@@ -29,14 +29,4 @@
     boolean isRcsFeatureCreated();
     boolean isMmTelFeatureCreated();
     void resetState();
-    void notifyRcsCapabilitiesStatusChanged(int capability);
-    boolean isRcsCapable(int capability, int radioTech);
-    boolean isRcsAvailable(int capability);
-    String getConfigString(int subId, int item);
-
-    // IMS registration status changed
-    void triggerImsOnRegistered(int radioTech);
-    void triggerImsOnRegistering(int radioTech);
-    void triggerImsOnDeregistered(in ImsReasonInfo info);
-    void triggerImsOnTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info);
 }
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
index b0bbdfb..9101ae5 100644
--- a/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
@@ -18,13 +18,9 @@
 
 import android.content.Intent;
 import android.os.IBinder;
-import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.cts.ImsUtils;
 import android.telephony.ims.cts.TestImsService;
-import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
-import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
-import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
 /**
@@ -60,49 +56,6 @@
         public void resetState() {
             TestExternalImsService.this.resetState();
         }
-
-        public String getConfigString(int subId, int item) {
-            ImsConfigImplBase imsConfig = TestExternalImsService.this.getImsService().getConfig(
-                    subId);
-            if (imsConfig != null) {
-                return imsConfig.getConfigString(item);
-            }
-            return null;
-        }
-
-        public void triggerImsOnRegistered(int imsRadioTech) {
-            ImsRegistrationImplBase imsReg = TestExternalImsService.this.getImsRegistration();
-            imsReg.onRegistered(imsRadioTech);
-        }
-
-        public void triggerImsOnRegistering(int imsRadioTech) {
-            ImsRegistrationImplBase imsReg = TestExternalImsService.this.getImsRegistration();
-            imsReg.onRegistering(imsRadioTech);
-        }
-
-        public void triggerImsOnDeregistered(ImsReasonInfo info) {
-            ImsRegistrationImplBase imsReg = TestExternalImsService.this.getImsRegistration();
-            imsReg.onDeregistered(info);
-        }
-
-        public void triggerImsOnTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
-            ImsRegistrationImplBase imsReg = TestExternalImsService.this.getImsRegistration();
-            imsReg.onTechnologyChangeFailed(imsRadioTech, info);
-        }
-
-        public void notifyRcsCapabilitiesStatusChanged(int capability) {
-            RcsImsCapabilities capabilities = new RcsImsCapabilities(capability);
-            getRcsFeature().notifyCapabilitiesStatusChanged(capabilities);
-        }
-
-        public boolean isRcsCapable(int capability, int radioTech) {
-            return getRcsFeature().queryCapabilityConfiguration(capability, radioTech);
-        }
-
-        public boolean isRcsAvailable(int capability) {
-            RcsImsCapabilities capabilityStatus = getRcsFeature().queryCapabilityStatus();
-            return capabilityStatus.isCapable(capability);
-        }
     }
 
     @Override
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java
index 3ca8ee4..4035372 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java
@@ -19,42 +19,59 @@
 
 import static junit.framework.Assert.fail;
 
-import android.content.Intent;
 import android.os.UserHandle;
+import android.telephony.CbGeoUtils.Geometry;
 import android.telephony.CellBroadcastIntents;
+import android.telephony.SmsCbEtwsInfo;
+import android.telephony.SmsCbLocation;
+import android.telephony.SmsCbMessage;
 
 import androidx.test.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.internal.telephony.gsm.SmsCbConstants;
 
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class CellBroadcastIntentsTest {
 
-    private static final String TEST_ACTION = "test_action";
+    private static final int TEST_MESSAGE_FORMAT = SmsCbMessage.MESSAGE_FORMAT_3GPP2;
+    private static final int TEST_GEO_SCOPE = SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE;
+    private static final int TEST_SERIAL = 1234;
+    private static final String TEST_PLMN = "111222";
+    private static final SmsCbLocation TEST_LOCATION = new SmsCbLocation(TEST_PLMN, -1, -1);
+    private static final int TEST_SERVICE_CATEGORY = 4097;
+    private static final String TEST_LANGUAGE = "en";
+    private static final String TEST_BODY = "test body";
+    private static final int TEST_PRIORITY = 0;
+    private static final int TEST_ETWS_WARNING_TYPE =
+            SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE;
+    private static final SmsCbEtwsInfo TEST_ETWS_INFO = new SmsCbEtwsInfo(TEST_ETWS_WARNING_TYPE,
+            false, false, false, null);
+
+    private static final int TEST_MAX_WAIT_TIME = 0;
+    private static final List<Geometry> TEST_GEOS = new ArrayList<>();
+    private static final int TEST_RECEIVED_TIME = 11000;
+    private static final int TEST_SLOT = 0;
+    private static final int TEST_SUB_ID = 1;
 
     @Test
     public void testGetIntentForBackgroundReceivers() {
         try {
-            CellBroadcastIntents.sendOrderedBroadcastForBackgroundReceivers(
-                    InstrumentationRegistry.getContext(), UserHandle.ALL, new Intent(TEST_ACTION),
-                    null, null, null, null, 0, null, null);
+            SmsCbMessage message = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE,
+                    TEST_SERIAL, TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                    TEST_PRIORITY, TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS,
+                    TEST_RECEIVED_TIME, TEST_SLOT, TEST_SUB_ID);
+
+            CellBroadcastIntents.sendSmsCbReceivedBroadcast(
+                    InstrumentationRegistry.getContext(), UserHandle.ALL, message,
+                    null, null, 0, TEST_SLOT);
         } catch (SecurityException e) {
             // expected
             return;
         }
         fail();
     }
-
-    @Test
-    public void testGetIntentForBackgroundReceiversWithPermission() {
-        ShellIdentityUtils.invokeStaticMethodWithShellPermissions(
-                () -> {
-                    CellBroadcastIntents.sendOrderedBroadcastForBackgroundReceivers(
-                            InstrumentationRegistry.getContext(), UserHandle.ALL,
-                            new Intent(TEST_ACTION),
-                            null, null, null, null, 0, null, null);
-                    return true;
-                });
-    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 4959248..af2d19b 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -42,6 +42,7 @@
 import android.net.wifi.WifiManager;
 import android.os.AsyncTask;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.PersistableBundle;
@@ -53,6 +54,7 @@
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.AvailableNetworkInfo;
 import android.telephony.CallAttributes;
+import android.telephony.CallForwardingInfo;
 import android.telephony.CallQuality;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
@@ -165,6 +167,8 @@
     private static final int MAX_FPLMN_NUM = 100;
     private static final int MIN_FPLMN_NUM = 3;
 
+    private static final String TEST_FORWARD_NUMBER = "54321";
+
     static {
         EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
         EMERGENCY_NUMBER_SOURCE_SET.add(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
@@ -187,6 +191,12 @@
         EMERGENCY_SERVICE_CATEGORY_SET.add(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AIEC);
     }
 
+    private static final String LOCATION_ACCESS_APP_CURRENT_PACKAGE =
+            CtsLocationAccessService.class.getPackage().getName();
+
+    private static final String LOCATION_ACCESS_APP_SDK28_PACKAGE =
+            CtsLocationAccessService.class.getPackage().getName() + ".sdk28";
+
     private int mTestSub;
     private TelephonyManagerTest.CarrierConfigReceiver mReceiver;
 
@@ -517,6 +527,8 @@
                 (tm) -> tm.isDataConnectionEnabled());
         ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
                 (tm) -> tm.isAnyRadioPoweredOn());
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+                (tm) -> tm.resetIms(tm.getSlotIndex()));
 
         // Verify TelephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions
         List<String> resultForGetCarrierPrivilegedApis =
@@ -533,11 +545,106 @@
     }
 
     @Test
+    public void testGetCallForwarding() {
+        List<Integer> callForwardingReasons = new ArrayList<>();
+        callForwardingReasons.add(CallForwardingInfo.REASON_UNCONDITIONAL);
+        callForwardingReasons.add(CallForwardingInfo.REASON_BUSY);
+        callForwardingReasons.add(CallForwardingInfo.REASON_NO_REPLY);
+        callForwardingReasons.add(CallForwardingInfo.REASON_NOT_REACHABLE);
+        callForwardingReasons.add(CallForwardingInfo.REASON_ALL);
+        callForwardingReasons.add(CallForwardingInfo.REASON_ALL_CONDITIONAL);
+
+        Set<Integer> callForwardingStatus = new HashSet<Integer>();
+        callForwardingStatus.add(CallForwardingInfo.STATUS_INACTIVE);
+        callForwardingStatus.add(CallForwardingInfo.STATUS_ACTIVE);
+        callForwardingStatus.add(CallForwardingInfo.STATUS_FDN_CHECK_FAILURE);
+        callForwardingStatus.add(CallForwardingInfo.STATUS_UNKNOWN_ERROR);
+        callForwardingStatus.add(CallForwardingInfo.STATUS_NOT_SUPPORTED);
+
+        for (int callForwardingReasonToGet : callForwardingReasons) {
+            Log.d(TAG, "[testGetCallForwarding] callForwardingReasonToGet: "
+                    + callForwardingReasonToGet);
+            CallForwardingInfo callForwardingInfo =
+                    ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                            (tm) -> tm.getCallForwarding(callForwardingReasonToGet));
+
+            assertNotNull(callForwardingInfo);
+            assertTrue(callForwardingStatus.contains(callForwardingInfo.getStatus()));
+            assertTrue(callForwardingReasons.contains(callForwardingInfo.getReason()));
+            callForwardingInfo.getNumber();
+            assertTrue(callForwardingInfo.getTimeoutSeconds() >= 0);
+        }
+    }
+
+    @Test
+    public void testSetCallForwarding() {
+        List<Integer> callForwardingReasons = new ArrayList<>();
+        callForwardingReasons.add(CallForwardingInfo.REASON_UNCONDITIONAL);
+        callForwardingReasons.add(CallForwardingInfo.REASON_BUSY);
+        callForwardingReasons.add(CallForwardingInfo.REASON_NO_REPLY);
+        callForwardingReasons.add(CallForwardingInfo.REASON_NOT_REACHABLE);
+        callForwardingReasons.add(CallForwardingInfo.REASON_ALL);
+        callForwardingReasons.add(CallForwardingInfo.REASON_ALL_CONDITIONAL);
+
+        // Enable Call Forwarding
+        for (int callForwardingReasonToEnable : callForwardingReasons) {
+            final CallForwardingInfo callForwardingInfoToEnable = new CallForwardingInfo(
+                    CallForwardingInfo.STATUS_ACTIVE,
+                    callForwardingReasonToEnable,
+                    TEST_FORWARD_NUMBER,
+                    1 /** time seconds */);
+            Log.d(TAG, "[testSetCallForwarding] Enable Call Forwarding. Status: "
+                    + CallForwardingInfo.STATUS_ACTIVE + " Reason: " + callForwardingReasonToEnable
+                    + " Number: " + TEST_FORWARD_NUMBER + " Time Seconds: 1");
+            ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                    (tm) -> tm.setCallForwarding(callForwardingInfoToEnable));
+        }
+
+        // Disable Call Forwarding
+        for (int callForwardingReasonToDisable : callForwardingReasons) {
+            final CallForwardingInfo callForwardingInfoToDisable = new CallForwardingInfo(
+                    CallForwardingInfo.STATUS_INACTIVE,
+                    callForwardingReasonToDisable,
+                    TEST_FORWARD_NUMBER,
+                    1 /** time seconds */);
+            Log.d(TAG, "[testSetCallForwarding] Disable Call Forwarding. Status: "
+                    + CallForwardingInfo.STATUS_INACTIVE + " Reason: "
+                    + callForwardingReasonToDisable + " Number: " + TEST_FORWARD_NUMBER
+                    + " Time Seconds: 1");
+            ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                    (tm) -> tm.setCallForwarding(callForwardingInfoToDisable));
+        }
+    }
+
+    @Test
+    public void testGetCallWaitingStatus() {
+        Set<Integer> callWaitingStatus = new HashSet<Integer>();
+        callWaitingStatus.add(TelephonyManager.CALL_WAITING_STATUS_ACTIVE);
+        callWaitingStatus.add(TelephonyManager.CALL_WAITING_STATUS_INACTIVE);
+        callWaitingStatus.add(TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR);
+        callWaitingStatus.add(TelephonyManager.CALL_WAITING_STATUS_NOT_SUPPORTED);
+
+        int status = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.getCallWaitingStatus());
+        assertTrue(callWaitingStatus.contains(status));
+    }
+
+    @Test
+    public void testSetCallWaitingStatus() {
+        ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                (tm) -> tm.setCallWaitingStatus(true));
+        ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                (tm) -> tm.setCallWaitingStatus(false));
+    }
+
+    @Test
     public void testCellLocationFinePermission() {
-        withRevokedPermission(() -> {
+        withRevokedPermission(LOCATION_ACCESS_APP_CURRENT_PACKAGE, () -> {
             try {
-                CellLocation cellLocation = (CellLocation) performLocationAccessCommand(
+                Bundle cellLocationBundle = (Bundle) performLocationAccessCommand(
                         CtsLocationAccessService.COMMAND_GET_CELL_LOCATION);
+                CellLocation cellLocation = cellLocationBundle == null ? null :
+                        CellLocation.newFromBundle(cellLocationBundle);
                 assertTrue(cellLocation == null || cellLocation.isEmpty());
             } catch (SecurityException e) {
                 // expected
@@ -555,12 +662,12 @@
 
     @Test
     public void testServiceStateLocationSanitization() {
-        withRevokedPermission(() -> {
+        withRevokedPermission(LOCATION_ACCESS_APP_CURRENT_PACKAGE, () -> {
                     ServiceState ss = (ServiceState) performLocationAccessCommand(
                             CtsLocationAccessService.COMMAND_GET_SERVICE_STATE);
                     assertServiceStateSanitization(ss, true);
 
-                    withRevokedPermission(() -> {
+                    withRevokedPermission(LOCATION_ACCESS_APP_CURRENT_PACKAGE, () -> {
                                 ServiceState ss1 = (ServiceState) performLocationAccessCommand(
                                         CtsLocationAccessService.COMMAND_GET_SERVICE_STATE);
                                 assertServiceStateSanitization(ss1, false);
@@ -574,12 +681,12 @@
     public void testServiceStateListeningWithoutPermissions() {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) return;
 
-        withRevokedPermission(() -> {
+        withRevokedPermission(LOCATION_ACCESS_APP_CURRENT_PACKAGE, () -> {
                     ServiceState ss = (ServiceState) performLocationAccessCommand(
                             CtsLocationAccessService.COMMAND_GET_SERVICE_STATE_FROM_LISTENER);
                     assertServiceStateSanitization(ss, true);
 
-                    withRevokedPermission(() -> {
+                    withRevokedPermission(LOCATION_ACCESS_APP_CURRENT_PACKAGE, () -> {
                                 ServiceState ss1 = (ServiceState) performLocationAccessCommand(
                                         CtsLocationAccessService
                                                 .COMMAND_GET_SERVICE_STATE_FROM_LISTENER);
@@ -592,7 +699,7 @@
 
     @Test
     public void testRegistryPermissionsForCellLocation() {
-        withRevokedPermission(() -> {
+        withRevokedPermission(LOCATION_ACCESS_APP_CURRENT_PACKAGE, () -> {
                     CellLocation cellLocation = (CellLocation) performLocationAccessCommand(
                             CtsLocationAccessService.COMMAND_LISTEN_CELL_LOCATION);
                     assertNull(cellLocation);
@@ -602,7 +709,7 @@
 
     @Test
     public void testRegistryPermissionsForCellInfo() {
-        withRevokedPermission(() -> {
+        withRevokedPermission(LOCATION_ACCESS_APP_CURRENT_PACKAGE, () -> {
                     CellLocation cellLocation = (CellLocation) performLocationAccessCommand(
                             CtsLocationAccessService.COMMAND_LISTEN_CELL_INFO);
                     assertNull(cellLocation);
@@ -610,11 +717,51 @@
                 Manifest.permission.ACCESS_FINE_LOCATION);
     }
 
+    @Test
+    public void testSdk28CellLocation() {
+        // Verify that a target-sdk 28 app can access cell location with ACCESS_COARSE_LOCATION, but
+        // not with no location permissions at all.
+        withRevokedPermission(LOCATION_ACCESS_APP_SDK28_PACKAGE, () -> {
+            try {
+                performLocationAccessCommandSdk28(
+                        CtsLocationAccessService.COMMAND_GET_CELL_LOCATION);
+            } catch (SecurityException e) {
+                fail("SDK28 should have access to cell location with coarse permission");
+            }
+
+            withRevokedPermission(LOCATION_ACCESS_APP_SDK28_PACKAGE, () -> {
+                try {
+                    Bundle cellLocationBundle = (Bundle) performLocationAccessCommandSdk28(
+                            CtsLocationAccessService.COMMAND_GET_CELL_LOCATION);
+                    CellLocation cellLocation = cellLocationBundle == null ? null :
+                            CellLocation.newFromBundle(cellLocationBundle);
+                    assertTrue(cellLocation == null || cellLocation.isEmpty());
+                } catch (SecurityException e) {
+                    // expected
+                }
+            }, Manifest.permission.ACCESS_COARSE_LOCATION);
+        }, Manifest.permission.ACCESS_FINE_LOCATION);
+
+    }
     private ICtsLocationAccessControl getLocationAccessAppControl() {
         Intent bindIntent = new Intent(CtsLocationAccessService.CONTROL_ACTION);
-        bindIntent.setComponent(new ComponentName(CtsLocationAccessService.class.getPackageName$(),
+        bindIntent.setComponent(new ComponentName(
+                LOCATION_ACCESS_APP_CURRENT_PACKAGE,
                 CtsLocationAccessService.class.getName()));
 
+        return bindLocationAccessControl(bindIntent);
+    }
+
+    private ICtsLocationAccessControl getLocationAccessAppControlSdk28() {
+        Intent bindIntent = new Intent(CtsLocationAccessService.CONTROL_ACTION);
+        bindIntent.setComponent(new ComponentName(
+                LOCATION_ACCESS_APP_SDK28_PACKAGE,
+                CtsLocationAccessService.class.getName()));
+
+        return bindLocationAccessControl(bindIntent);
+    }
+
+    private ICtsLocationAccessControl bindLocationAccessControl(Intent bindIntent) {
         LinkedBlockingQueue<ICtsLocationAccessControl> pipe =
                 new LinkedBlockingQueue<>();
         getContext().bindService(bindIntent, new ServiceConnection() {
@@ -649,16 +796,25 @@
         return null;
     }
 
-    private void withRevokedPermission(Runnable r, String permission) {
+    private Object performLocationAccessCommandSdk28(String command) {
+        ICtsLocationAccessControl control = getLocationAccessAppControlSdk28();
+        try {
+            List ret = control.performCommand(command);
+            if (!ret.isEmpty()) return ret.get(0);
+        } catch (RemoteException e) {
+            fail("Remote exception");
+        }
+        return null;
+    }
+
+    private void withRevokedPermission(String packageName, Runnable r, String permission) {
         InstrumentationRegistry.getInstrumentation()
-                .getUiAutomation().revokeRuntimePermission(
-                CtsLocationAccessService.class.getPackageName$(), permission);
+                .getUiAutomation().revokeRuntimePermission(packageName, permission);
         try {
             r.run();
         } finally {
             InstrumentationRegistry.getInstrumentation()
-                    .getUiAutomation().grantRuntimePermission(
-                    CtsLocationAccessService.class.getPackageName$(), permission);
+                    .getUiAutomation().grantRuntimePermission(packageName, permission);
         }
     }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
index 151d899..feda07b 100644
--- a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
@@ -267,7 +267,7 @@
         assertEquals(EuiccManager.ERROR_EUICC_MISSING, 10006);
         assertEquals(EuiccManager.ERROR_UNSUPPORTED_VERSION, 10007);
         assertEquals(EuiccManager.ERROR_SIM_MISSING, 10008);
-        assertEquals(EuiccManager.ERROR_EUICC_GSMA_INSTALL_ERROR, 10009);
+        assertEquals(EuiccManager.ERROR_INSTALL_PROFILE, 10009);
         assertEquals(EuiccManager.ERROR_DISALLOWED_BY_PPR, 10010);
         assertEquals(EuiccManager.ERROR_ADDRESS_MISSING, 10011);
         assertEquals(EuiccManager.ERROR_CERTIFICATE_ERROR, 10012);
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
index a917d93..f96928a 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
@@ -34,6 +34,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.feature.MmTelFeature;
 
@@ -140,9 +141,10 @@
     @Test
     public void testGetVoWiFiSetting_noPermission() {
         try {
-            ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+            ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
             boolean isEnabled = mMmTelManager.isVoWiFiSettingEnabled();
-            fail("Expected SecurityException for missing permissoins");
+            fail("Expected SecurityException for missing permissions");
         } catch (SecurityException ex) {
             /* Expected */
         }
@@ -171,7 +173,8 @@
         CountDownLatch contentObservedLatch = new CountDownLatch(1);
         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
 
-        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
                 ImsMmTelManager::isAdvancedCallingSettingEnabled);
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
@@ -206,7 +209,8 @@
         CountDownLatch contentObservedLatch = new CountDownLatch(1);
         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
 
-        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
                 ImsMmTelManager::isVtSettingEnabled);
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
@@ -244,7 +248,8 @@
         CountDownLatch contentObservedLatch = new CountDownLatch(1);
         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
 
-        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
 
         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
                 ImsMmTelManager::isVoWiFiSettingEnabled);
@@ -278,7 +283,8 @@
         CountDownLatch contentObservedLatch = new CountDownLatch(1);
         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
 
-        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
                 ImsMmTelManager::isVoWiFiRoamingSettingEnabled);
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
@@ -304,7 +310,8 @@
             return;
         }
         try {
-            ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+            ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
             int oldMode = mMmTelManager.getVoWiFiModeSetting();
             fail("Expected SecurityException for missing permissoins");
         } catch (SecurityException ex) {
@@ -322,7 +329,8 @@
             return;
         }
         try {
-            ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+            ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
             int oldMode = mMmTelManager.getVoWiFiRoamingModeSetting();
             fail("Expected SecurityException for missing permissoins");
         } catch (SecurityException ex) {
@@ -350,7 +358,8 @@
         CountDownLatch contentObservedLatch = new CountDownLatch(1);
         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
 
-        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
         int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
                 ImsMmTelManager::getVoWiFiModeSetting);
         // Keep the mode in the bounds 0-2
@@ -389,7 +398,8 @@
         CountDownLatch contentObservedLatch = new CountDownLatch(1);
         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
 
-        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
         int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
                 ImsMmTelManager::getVoWiFiRoamingModeSetting);
         // Keep the mode in the bounds 0-2
@@ -418,7 +428,8 @@
             return;
         }
 
-        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
         // setRttCapabilitySetting
         try {
             mMmTelManager.setRttCapabilitySetting(false);
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index 78705d2..d5a61c8 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -40,7 +40,6 @@
 import android.telephony.TelephonyManager;
 import android.telephony.cts.AsyncSmsMessageListener;
 import android.telephony.cts.SmsReceiverHelper;
-import android.telephony.cts.externalimsservice.ITestExternalImsService;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
@@ -51,6 +50,7 @@
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
+import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Base64;
@@ -671,7 +671,8 @@
     }
 
     private Integer getFeatureState() throws Exception {
-        ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
         LinkedBlockingQueue<Integer> state = new LinkedBlockingQueue<>(1);
         ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mmTelManager,
                 (m) -> m.getFeatureState(Runnable::run, state::offer), ImsException.class);
@@ -722,7 +723,8 @@
         final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         // Latch will count down here (we callback on the state during registration).
         try {
-            ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+            ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
             mmTelManager.registerImsRegistrationCallback(getContext().getMainExecutor(), callback);
             fail("registerImsRegistrationCallback requires READ_PRECISE_PHONE_STATE permission.");
         } catch (SecurityException e) {
@@ -731,7 +733,8 @@
 
         try {
             automan.adoptShellPermissionIdentity();
-            ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+            ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
             mmTelManager.registerImsRegistrationCallback(getContext().getMainExecutor(), callback);
         } finally {
             automan.dropShellPermissionIdentity();
@@ -759,14 +762,16 @@
 
         try {
             automan.adoptShellPermissionIdentity();
-            ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+            ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
             mmTelManager.unregisterImsRegistrationCallback(callback);
         } finally {
             automan.dropShellPermissionIdentity();
         }
 
         try {
-            ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+            ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
             mmTelManager.unregisterImsRegistrationCallback(callback);
             fail("unregisterImsRegistrationCallback requires READ_PRECISE_PHONE_STATE permission.");
         } catch (SecurityException e) {
@@ -787,42 +792,42 @@
         }
 
         // Connect to device ImsService with RcsFeature
-        triggerFrameworkConnectToDeviceImsServiceBindRcsFeature();
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
         ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
 
-        ITestExternalImsService testImsService = sServiceConnector.getExternalService();
         // Wait for the framework to set the capabilities on the ImsService
-        testImsService.waitForLatchCountdown(TestImsService.LATCH_RCS_CAP_SET);
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_RCS_CAP_SET);
 
         // Start de-registered
-        sServiceConnector.getExternalService().triggerImsOnDeregistered(
+        sServiceConnector.getCarrierService().getImsRegistration().onDeregistered(
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
 
         LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
         RegistrationManager.RegistrationCallback callback =
                 new RegistrationManager.RegistrationCallback() {
-            @Override
-            public void onRegistered(int imsTransportType) {
-                mQueue.offer(imsTransportType);
-            }
+                    @Override
+                    public void onRegistered(int imsTransportType) {
+                        mQueue.offer(imsTransportType);
+                    }
 
-            @Override
-            public void onRegistering(int imsTransportType) {
-                mQueue.offer(imsTransportType);
-            }
+                    @Override
+                    public void onRegistering(int imsTransportType) {
+                        mQueue.offer(imsTransportType);
+                    }
 
-            @Override
-            public void onUnregistered(ImsReasonInfo info) {
-                mQueue.offer(info.getCode());
-            }
+                    @Override
+                    public void onUnregistered(ImsReasonInfo info) {
+                        mQueue.offer(info.getCode());
+                    }
 
-            @Override
-            public void onTechnologyChangeFailed(int imsTransportType, ImsReasonInfo info) {
-                mQueue.offer(imsTransportType);
-                mQueue.offer(info.getCode());
-            }
-        };
+                    @Override
+                    public void onTechnologyChangeFailed(int imsTransportType, ImsReasonInfo info) {
+                        mQueue.offer(imsTransportType);
+                        mQueue.offer(info.getCode());
+                    }
+                };
 
         final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         try {
@@ -835,17 +840,17 @@
         assertEquals(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, waitForIntResult(mQueue));
 
         // Start registration
-        sServiceConnector.getExternalService().triggerImsOnRegistering(
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
                 ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
 
         // Complete registration
-        sServiceConnector.getExternalService().triggerImsOnRegistered(
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
                 ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
 
         // Fail handover to IWLAN
-        sServiceConnector.getExternalService().triggerImsOnTechnologyChangeFailed(
+        sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
                 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
@@ -865,7 +870,8 @@
         if (!ImsUtils.shouldTestImsService()) {
             return;
         }
-        RegistrationManager regManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RegistrationManager regManager = imsManager.getImsMmTelManager(sTestSub);
         LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
 
         triggerFrameworkConnectToCarrierImsService();
@@ -899,8 +905,7 @@
                     }
                 };
 
-        ImsMmTelManager mmTelManager =
-                ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
         ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mmTelManager,
                 (m) -> m.registerImsRegistrationCallback(getContext().getMainExecutor(), callback),
                 ImsException.class);
@@ -956,12 +961,12 @@
         }
 
         // Connect to device ImsService with RcsFeature
-        triggerFrameworkConnectToDeviceImsServiceBindRcsFeature();
-        ITestExternalImsService testImsService = sServiceConnector.getExternalService();
-        testImsService.waitForLatchCountdown(TestImsService.LATCH_RCS_CAP_SET);
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_RCS_CAP_SET);
 
         // Start de-registered
-        sServiceConnector.getExternalService().triggerImsOnDeregistered(
+        sServiceConnector.getCarrierService().getImsRegistration().onDeregistered(
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
 
@@ -1003,21 +1008,21 @@
                 AccessNetworkConstants.TRANSPORT_TYPE_INVALID);
 
         // Start registration
-        sServiceConnector.getExternalService().triggerImsOnRegistering(
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
                 ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERING);
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // Complete registration
-        sServiceConnector.getExternalService().triggerImsOnRegistered(
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
                 ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // Fail handover to IWLAN
-        sServiceConnector.getExternalService().triggerImsOnTechnologyChangeFailed(
+        sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
                 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
@@ -1026,7 +1031,7 @@
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // handover to IWLAN
-        sServiceConnector.getExternalService().triggerImsOnRegistered(
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
                 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
@@ -1040,7 +1045,8 @@
             return;
         }
 
-        ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
 
         triggerFrameworkConnectToCarrierImsService();
 
@@ -1129,7 +1135,11 @@
 
     @Test
     public void testProvisioningManagerNotifyAutoConfig() throws Exception {
-        triggerFrameworkConnectToDeviceImsServiceBindRcsFeature();
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
 
         ProvisioningManager provisioningManager =
                 ProvisioningManager.createForSubscriptionId(sTestSub);
@@ -1139,15 +1149,15 @@
             automan.adoptShellPermissionIdentity();
             provisioningManager.notifyRcsAutoConfigurationReceived(
                     TEST_AUTOCONFIG_CONTENT.getBytes(), false);
+            ImsConfigImplBase config = sServiceConnector.getCarrierService().getConfig();
+            Assert.assertNotNull(config);
             assertEquals(TEST_AUTOCONFIG_CONTENT,
-                    sServiceConnector.getExternalService().getConfigString(sTestSlot,
-                            ImsUtils.ITEM_NON_COMPRESSED));
+                    config.getConfigString(ImsUtils.ITEM_NON_COMPRESSED));
 
             provisioningManager.notifyRcsAutoConfigurationReceived(
                     TEST_AUTOCONFIG_CONTENT.getBytes(), true);
             assertEquals(TEST_AUTOCONFIG_CONTENT,
-                    sServiceConnector.getExternalService().getConfigString(sTestSlot,
-                            ImsUtils.ITEM_COMPRESSED));
+                    config.getConfigString(ImsUtils.ITEM_COMPRESSED));
         } finally {
             automan.dropShellPermissionIdentity();
         }
@@ -1165,17 +1175,20 @@
         }
 
         // Connect to device ImsService with RcsFeature
-        triggerFrameworkConnectToDeviceImsServiceBindRcsFeature();
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
 
         int registrationTech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
         ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
 
-        ITestExternalImsService testImsService = sServiceConnector.getExternalService();
         // Wait for the framework to set the capabilities on the ImsService
-        testImsService.waitForLatchCountdown(TestImsService.LATCH_RCS_CAP_SET);
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_RCS_CAP_SET);
         // Make sure we start off with none-capability
-        testImsService.triggerImsOnRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
-        testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_NONE);
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        RcsImsCapabilities noCapabilities = new RcsImsCapabilities(RCS_CAP_NONE);
+        sServiceConnector.getCarrierService().getRcsFeature()
+                .notifyCapabilitiesStatusChanged(noCapabilities);
 
         // Make sure the capabilities match the API getter for capabilities
         final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -1183,7 +1196,9 @@
         try {
             automan.adoptShellPermissionIdentity();
             // Make sure we are tracking voice capability over LTE properly.
-            assertEquals(testImsService.isRcsAvailable(RCS_CAP_PRESENCE),
+            RcsImsCapabilities availability = sServiceConnector.getCarrierService()
+                    .getRcsFeature().queryCapabilityStatus();
+            assertEquals(availability.isCapable(RCS_CAP_PRESENCE),
                     imsRcsManager.isAvailable(RCS_CAP_PRESENCE));
         } finally {
             automan.dropShellPermissionIdentity();
@@ -1238,7 +1253,9 @@
         }
 
         // Notify the SIP OPTIONS capability status changed
-        testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_OPTIONS);
+        RcsImsCapabilities optionsCap = new RcsImsCapabilities(RCS_CAP_OPTIONS);
+        sServiceConnector.getCarrierService().getRcsFeature()
+                .notifyCapabilitiesStatusChanged(optionsCap);
         capCb = waitForResult(mQueue);
 
         // The SIP OPTIONS capability from onAvailabilityChanged should be enabled.
@@ -1536,6 +1553,22 @@
         Thread.sleep(1000);
     }
 
+    private void triggerFrameworkConnectToLocalImsServiceBindRcsFeature() throws Exception {
+        // Connect to the ImsService with the RCS feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+                .build()));
+        // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS);
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_RCS_READY);
+        // Make sure the RcsFeature was created in the test service.
+        assertNotNull("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
+                + "called!", sServiceConnector.getCarrierService().getRcsFeature());
+    }
+
     private void triggerFrameworkConnectToCarrierImsService() throws Exception {
         // Connect to the ImsService with the MmTel feature.
         assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
@@ -1551,20 +1584,6 @@
                 sServiceConnector.getCarrierService().getMmTelFeature());
     }
 
-    private void triggerFrameworkConnectToDeviceImsServiceBindRcsFeature() throws Exception {
-        // Connect to the ImsService with the RCS feature.
-        assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
-                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
-                .build()));
-        // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
-        // Framework did not call it.
-        sServiceConnector.getExternalService().waitForLatchCountdown(
-                TestImsService.LATCH_CREATE_RCS);
-        // Make sure the RcsFeature was created in the test service.
-        assertTrue("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
-                + "called!", sServiceConnector.getExternalService().isRcsFeatureCreated());
-    }
-
     private void verifyRegistrationState(RegistrationManager regManager, int expectedState)
             throws Exception {
         LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
new file mode 100644
index 0000000..8ab1f78
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+package android.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Looper;
+import android.telecom.PhoneAccount;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.RcsUceAdapter;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsUceAdapterTest {
+
+    private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    private static final Uri TEST_NUMBER_URI =
+            Uri.fromParts(PhoneAccount.SCHEME_TEL, "6505551212", null);
+
+    @BeforeClass
+    public static void beforeAllTests() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        sTestSub = ImsUtils.getPreferredActiveSubId();
+
+        if (Looper.getMainLooper() == null) {
+            Looper.prepareMainLooper();
+        }
+    }
+
+    @Before
+    public void beforeTest() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        if (!SubscriptionManager.isValidSubscriptionId(sTestSub)) {
+            fail("This test requires that there is a SIM in the device!");
+        }
+    }
+
+    @Test
+    public void testGetAndSetUceSetting() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter adapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("RcsUceAdapter can not be null!", adapter);
+
+        Boolean isEnabled = null;
+        try {
+            isEnabled = ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+                    adapter, RcsUceAdapter::isUceSettingEnabled, ImsException.class,
+                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+            assertNotNull(isEnabled);
+
+            boolean userSetIsEnabled = isEnabled;
+            ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
+                    adapter, a -> a.setUceSettingEnabled(!userSetIsEnabled), ImsException.class,
+                    "android.permission.MODIFY_PHONE_STATE");
+
+
+            Boolean setResult = ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+                    adapter, RcsUceAdapter::isUceSettingEnabled, ImsException.class,
+                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+            assertNotNull(setResult);
+            assertEquals("Incorrect setting!", !userSetIsEnabled, setResult);
+        } catch (ImsException e) {
+            if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
+                fail("failed getting UCE setting with code: " + e.getCode());
+            }
+        } finally {
+            if (isEnabled != null) {
+                boolean userSetIsEnabled = isEnabled;
+                // set back to user preference
+                ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
+                        adapter, a -> a.setUceSettingEnabled(userSetIsEnabled), ImsException.class,
+                        "android.permission.MODIFY_PHONE_STATE");
+            }
+        }
+    }
+
+    @Test
+    public void testMethodPermissions() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // requestCapabilities
+        ArrayList<Uri> numbers = new ArrayList<>(1);
+        numbers.add(TEST_NUMBER_URI);
+        try {
+            ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(uceAdapter,
+                    (m) -> m.requestCapabilities(Runnable::run, numbers,
+                            new RcsUceAdapter.CapabilitiesCallback() {
+                            }), ImsException.class,
+                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+        } catch (SecurityException e) {
+            fail("requestCapabilities should succeed with READ_PRIVILEGED_PHONE_STATE.");
+        } catch (ImsException e) {
+            // unsupported is a valid fail cause.
+            if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
+                fail("request capabilities failed with code " + e.getCode());
+            }
+        }
+
+        try {
+            uceAdapter.requestCapabilities(Runnable::run, numbers,
+                    new RcsUceAdapter.CapabilitiesCallback() {});
+            fail("requestCapabilities should require READ_PRIVILEGED_PHONE_STATE.");
+        } catch (SecurityException e) {
+            //expected
+        }
+
+        // getUcePublishState
+        try {
+            Integer result = ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+                    uceAdapter, RcsUceAdapter::getUcePublishState, ImsException.class,
+                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+            assertNotNull("result from getUcePublishState should not be null", result);
+        } catch (SecurityException e) {
+            fail("getUcePublishState should succeed with READ_PRIVILEGED_PHONE_STATE.");
+        } catch (ImsException e) {
+            // unsupported is a valid fail cause.
+            if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
+                fail("getUcePublishState failed with code " + e.getCode());
+            }
+        }
+        try {
+            uceAdapter.getUcePublishState();
+            fail("requestCapabilities should require READ_PRIVILEGED_PHONE_STATE.");
+        } catch (SecurityException e) {
+            //expected
+        }
+
+        //isUceSettingEnabled
+        Boolean isUceSettingEnabledResult = null;
+        try {
+            isUceSettingEnabledResult =
+                    ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+                    uceAdapter, RcsUceAdapter::isUceSettingEnabled, ImsException.class,
+                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+            assertNotNull("result from isUceSettingEnabled should not be null",
+                    isUceSettingEnabledResult);
+        } catch (SecurityException e) {
+            fail("isUceSettingEnabled should succeed with READ_PRIVILEGED_PHONE_STATE.");
+        } catch (ImsException e) {
+            // unsupported is a valid fail cause.
+            if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
+                fail("isUceSettingEnabled failed with code " + e.getCode());
+            }
+        }
+        try {
+            uceAdapter.getUcePublishState();
+            fail("isUceSettingEnabled should require READ_PRIVILEGED_PHONE_STATE.");
+        } catch (SecurityException e) {
+            //expected
+        }
+
+        //setUceSettingEnabled
+        boolean isUceSettingEnabled =
+                (isUceSettingEnabledResult == null ? false : isUceSettingEnabledResult);
+        try {
+            ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(uceAdapter,
+                    (m) -> m.setUceSettingEnabled(isUceSettingEnabled), ImsException.class,
+                    "android.permission.MODIFY_PHONE_STATE");
+        } catch (SecurityException e) {
+            fail("setUceSettingEnabled should succeed with MODIFY_PHONE_STATE.");
+        } catch (ImsException e) {
+            // unsupported is a valid fail cause.
+            if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
+                fail("setUceSettingEnabled failed with code " + e.getCode());
+            }
+        }
+
+        try {
+            uceAdapter.requestCapabilities(Runnable::run, numbers,
+                    new RcsUceAdapter.CapabilitiesCallback() {});
+            fail("setUceSettingEnabled should require MODIFY_PHONE_STATE.");
+        } catch (SecurityException e) {
+            //expected
+        }
+    }
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
index ef7702f..eb3fc18 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -299,4 +299,8 @@
             return sImsRegistrationImplBase;
         }
     }
+
+    public ImsConfigImplBase getConfig() {
+        return mTestImsConfig;
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index e9ad80d..fd19757 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -516,19 +516,19 @@
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_SHORT, toast.getDuration());
         View view = toast.getView();
-        assertNotNull(view);
+        assertNull(view);
 
         toast = Toast.makeText(mContext, "cts", Toast.LENGTH_LONG);
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_LONG, toast.getDuration());
         view = toast.getView();
-        assertNotNull(view);
+        assertNull(view);
 
         toast = Toast.makeText(mContext, null, Toast.LENGTH_LONG);
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_LONG, toast.getDuration());
         view = toast.getView();
-        assertNotNull(view);
+        assertNull(view);
     }
 
     @UiThreadTest
@@ -545,13 +545,13 @@
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_LONG, toast.getDuration());
         View view = toast.getView();
-        assertNotNull(view);
+        assertNull(view);
 
         toast = Toast.makeText(mContext, R.string.hello_android, Toast.LENGTH_SHORT);
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_SHORT, toast.getDuration());
         view = toast.getView();
-        assertNotNull(view);
+        assertNull(view);
     }
 
     @UiThreadTest
@@ -592,10 +592,10 @@
     }
 
     @UiThreadTest
-    @Test(expected=RuntimeException.class)
-    public void testSetTextFromStringNullView() {
+    @Test(expected = IllegalStateException.class)
+    public void testSetTextFromStringNonNullView() {
         Toast toast = Toast.makeText(mContext, R.string.text, Toast.LENGTH_LONG);
-        toast.setView(null);
+        toast.setView(new TextView(mContext));
         toast.setText(null);
     }
 
diff --git a/tests/tests/widget29/AndroidTest.xml b/tests/tests/widget29/AndroidTest.xml
index 39d3911..e48e8ae 100644
--- a/tests/tests/widget29/AndroidTest.xml
+++ b/tests/tests/widget29/AndroidTest.xml
@@ -22,6 +22,11 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsWidgetTestCases29.apk" />
     </target_preparer>
+    <!-- TODO(b/144152069): Remove this when feature is gated on targetSdk -->
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="am compat disable CHANGE_TEXT_TOASTS_IN_THE_SYSTEM android.widget.cts29" />
+        <option name="teardown-command" value="am compat reset CHANGE_TEXT_TOASTS_IN_THE_SYSTEM android.widget.cts29" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.widget.cts29" />
         <option name="runtime-hint" value="11m55s" />
diff --git a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
index 1ca3cfa..216d764 100644
--- a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
@@ -490,6 +490,7 @@
         charsKeyNames.add(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getName());
         charsKeyNames.add(CameraCharacteristics.SCALER_CROPPING_TYPE.getName());
         charsKeyNames.add(CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS.getName());
+        charsKeyNames.add(CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.getName());
         charsKeyNames.add(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1.getName());
         charsKeyNames.add(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2.getName());
         charsKeyNames.add(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1.getName());