Merge "Add CTS tests for CBRS APIs"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9042e16..e2c1901 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -23,3 +23,5 @@
                       tests/tests/view/
                       tests/tests/widget/
                       common/device-side/util/
+
+ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
diff --git a/apps/CtsVerifier/res/layout/biometric_test_main.xml b/apps/CtsVerifier/res/layout/biometric_test_main.xml
index 75a42f9..476e355 100644
--- a/apps/CtsVerifier/res/layout/biometric_test_main.xml
+++ b/apps/CtsVerifier/res/layout/biometric_test_main.xml
@@ -20,28 +20,51 @@
     android:padding="10dip"
     >
 
-    <Button android:id="@+id/biometric_start_test1_button"
+    <Button android:id="@+id/biometric_enroll_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_above="@+id/biometric_start_test_not_secured"
+        android:layout_centerHorizontal="true"
+        android:text="@string/biometric_enroll"
+        android:visibility="invisible"
+        />
+
+    <Button android:id="@+id/biometric_start_test_not_secured"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerInParent="true"
         android:text="@string/biometric_start_test1"
         />
 
-    <Button android:id="@+id/biometric_enroll_button"
+    <Button android:id="@+id/biometric_start_test_none_enrolled"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_above="@+id/biometric_start_test2_button"
         android:layout_centerHorizontal="true"
-        android:text="@string/biometric_enroll"
+        android:layout_below="@+id/biometric_start_test_not_secured"
+        android:text="@string/biometric_start_test2"
+        android:visibility="invisible"
         />
 
-    <Button android:id="@+id/biometric_start_test2_button"
+    <Button android:id="@+id/biometric_start_test_credential_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:text="@string/biometric_start_test2"
+        android:layout_below="@+id/biometric_start_test_none_enrolled"
+        android:layout_centerHorizontal="true"
+        android:text="@string/biometric_start_test3"
+        android:visibility="invisible"
         />
 
+    <Button android:id="@+id/biometric_start_test_authenticate_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/biometric_start_test_fallback_button"
+        android:layout_centerHorizontal="true"
+        android:text="@string/biometric_start_test4"
+        android:visibility="invisible"
+        />
+
+
+
     <include android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 4ee6926..a6bb079 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -157,6 +157,8 @@
     <string name="biometric_enroll">Enroll</string>
     <string name="biometric_start_test1">Start Test 1</string>
     <string name="biometric_start_test2">Start Test 2</string>
+    <string name="biometric_start_test3">Start Test 3</string>
+    <string name="biometric_start_test4">Start Test 4</string>
 
     <!-- Strings for lock bound keys test -->
     <string name="sec_lock_bound_key_test">Lock Bound Keys Test</string>
@@ -1448,10 +1450,8 @@
         Test failed.\n\nUnexpected error. Check logcat.</string>
 
     <string name="wifi_status_initiating_scan">Initiating scan.</string>
-    <string name="wifi_status_scan_failure">Unable to initiate scan.</string>
-    <string name="wifi_status_open_network_not_found">Unable to find any open network in scan results.</string>
+    <string name="wifi_status_scan_failure">Unable to initiate scan or find any open network in scan results.</string>
     <string name="wifi_status_connected_to_other_network">Connected to some other network on the device. Please ensure that there is no saved networks on the device.</string>
-
     <string name="wifi_status_initiating_network_request">Initiating network request.</string>
     <string name="wifi_status_network_wait_for_available">Waiting for network connection. Please click the network in the dialog that pops up for approving the request.</string>
     <string name="wifi_status_network_available">"Connected to network."</string>
@@ -1487,9 +1487,9 @@
     <string name="wifi_test_network_suggestion">Network Suggestion tests</string>
     <string name="wifi_test_network_suggestion_ssid">Network suggestion with SSID.</string>
     <string name="wifi_test_network_suggestion_ssid_info">Tests whether the API can be used to suggest a network with SSID to the device and the device connects to it.</string>
-    <string name="wifi_test_network_suggestion_ssid_bssid">Network Request with a specific SSID and BSSID.</string>
+    <string name="wifi_test_network_suggestion_ssid_bssid">Network suggestion with SSID and BSSID.</string>
     <string name="wifi_test_network_suggestion_ssid_bssid_info">Tests whether the API can be used to suggest a network with SSID and specific BSSID to the device and the device connects to it.</string>
-    <string name="wifi_test_network_suggestion_ssid_post_connect">Network Request with a specific SSID and BSSID.</string>
+    <string name="wifi_test_network_suggestion_ssid_post_connect">Network suggestion with SSID and post connection broadcast.</string>
     <string name="wifi_test_network_suggestion_ssid_post_connect_info">Tests whether the API can be used to suggest a network with SSID to the device and the device connects to it and sends the post connect broadcast back to the app.</string>
 
     <!-- Strings for P2pTestActivity -->
@@ -1724,6 +1724,11 @@
     <string name="aware_status_lifecycle_failed">Discovery lifecycle FAILURE!</string>
     <string name="aware_status_lifecycle_ok">Discovery lifecycle validated!</string>
 
+    <string name="aware_status_socket_failure">Failure on socket connection setup!</string>
+    <string name="aware_status_socket_server_socket_started">ServerSocket started on port %1$d!</string>
+    <string name="aware_status_socket_server_info_rx">Peer server info: IPv6=%1$s @ port=%2$d!</string>
+    <string name="aware_status_socket_server_message_from_peer">Message from peer: \'%1$s\'</string>
+
     <string name="aware_data_path_open_unsolicited_publish">Data Path: Open: Unsolicited Publish</string>
     <string name="aware_data_path_open_unsolicited_publish_info">The publisher is now ready.\n\nOn the other device: start the \'Data Path: Open: Unsolicited/Passive\' / \'Subscribe\' test.</string>
     <string name="aware_data_path_open_passive_subscribe">Data Path: Open: Passive Subscribe</string>
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 31b43b4..ac9c465 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
@@ -17,6 +17,7 @@
 package com.android.cts.verifier.biometrics;
 
 import android.Manifest;
+import android.app.KeyguardManager;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -49,17 +50,29 @@
     private static final String BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL";
     private static final int BIOMETRIC_PERMISSION_REQUEST_CODE = 0;
 
-    private static final int TEST_NONE_ENROLLED = 1;
-    private static final int TEST_ENROLLED = 2;
+    // Test that BiometricPrompt setAllowDeviceCredentials returns ERROR_NO_DEVICE_CREDENTIAL when
+    // pin, pattern, password is not set.
+    private static final int TEST_NOT_SECURED = 1;
+    // Test that BiometricPrompt returns BIOMETRIC_ERROR_NO_BIOMETRICS when BiometricManager
+    // states BIOMETRIC_ERROR_NONE_ENROLLED.
+    private static final int TEST_NONE_ENROLLED = 2;
+    // Test that BiometricPrompt setAllowDeviceCredentials can authenticate when no biometrics are
+    // enrolled.
+    private static final int TEST_DEVICE_CREDENTIAL = 3;
+    // Test that authentication can succeed when biometrics are enrolled.
+    private static final int TEST_AUTHENTICATE = 4;
 
     private BiometricManager mBiometricManager;
+    private KeyguardManager mKeyguardManager;
     private Handler mHandler = new Handler(Looper.getMainLooper());
     private CancellationSignal mCancellationSignal;
-    private int mExpectedError;
     private int mCurrentTest;
+
     private Button mButtonEnroll;
-    private Button mButtonTest1;
-    private Button mButtonTest2;
+    private Button mButtonTestNotSecured;
+    private Button mButtonTestNoneEnrolled;
+    private Button mButtonTestCredential;
+    private Button mButtonTestAuthenticate;
 
     private Executor mExecutor = (runnable) -> {
         mHandler.post(runnable);
@@ -69,27 +82,45 @@
             new BiometricPrompt.AuthenticationCallback() {
         @Override
         public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
-            if (mCurrentTest == TEST_NONE_ENROLLED) {
-                showToastAndLog("This should be impossible, please capture a bug report");
-            } else if (mCurrentTest == TEST_ENROLLED) {
-                showToastAndLog("Authenticated. You passed the test.");
+            if (mCurrentTest == TEST_NOT_SECURED) {
+                showToastAndLog("This should be impossible, please capture a bug report "
+                        + mCurrentTest);
+            } else if (mCurrentTest == TEST_NONE_ENROLLED) {
+                showToastAndLog("This should be impossible, please capture a bug report"
+                        + mCurrentTest);
+            } else if (mCurrentTest == TEST_DEVICE_CREDENTIAL) {
+                showToastAndLog("Please enroll a biometric and start the next test");
+                mButtonTestCredential.setEnabled(false);
+                mButtonEnroll.setVisibility(View.VISIBLE);
+                mButtonTestAuthenticate.setVisibility(View.VISIBLE);
+            } else if (mCurrentTest == TEST_AUTHENTICATE) {
+                showToastAndLog("You have passed the test!");
+                mButtonTestAuthenticate.setEnabled(false);
                 getPassButton().setEnabled(true);
             }
         }
 
         @Override
         public void onAuthenticationError(int errorCode, CharSequence errString) {
-            if (mCurrentTest == TEST_NONE_ENROLLED) {
-                if (errorCode == mExpectedError) {
-                    mButtonTest1.setVisibility(View.INVISIBLE);
-                    mButtonTest2.setVisibility(View.VISIBLE);
-                    mButtonEnroll.setVisibility(View.VISIBLE);
-                    showToastAndLog("Please enroll a biometric and start the next test");
+            if (mCurrentTest == TEST_NOT_SECURED) {
+                if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL) {
+                    showToastAndLog("Please start the next test");
+                    mButtonTestNotSecured.setEnabled(false);
+                    mButtonTestNoneEnrolled.setVisibility(View.VISIBLE);
                 } else {
-                    showToastAndLog("Expected: " + mExpectedError +
-                            " Actual: " + errorCode + " " + errString);
+                    showToastAndLog("Error: " + errorCode + " " + errString);
                 }
-            } else if (mCurrentTest == TEST_ENROLLED) {
+            } else if (mCurrentTest == TEST_NONE_ENROLLED) {
+                if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS) {
+                    mButtonTestNoneEnrolled.setEnabled(false);
+                    mButtonTestCredential.setVisibility(View.VISIBLE);
+                    showToastAndLog("Please start the next test");
+                } else {
+                    showToastAndLog("Error: " + errorCode + " " + errString);
+                }
+            } else if (mCurrentTest == TEST_DEVICE_CREDENTIAL) {
+                showToastAndLog(errString.toString() + " Please try again");
+            } else if (mCurrentTest == TEST_AUTHENTICATE) {
                 showToastAndLog(errString.toString() + " Please try again");
             }
         }
@@ -108,11 +139,12 @@
         getPassButton().setEnabled(false);
 
         mBiometricManager = getApplicationContext().getSystemService(BiometricManager.class);
+        mKeyguardManager = getApplicationContext().getSystemService(KeyguardManager.class);
         mButtonEnroll = findViewById(R.id.biometric_enroll_button);
-        mButtonEnroll.setVisibility(View.INVISIBLE);
-        mButtonTest1 = findViewById(R.id.biometric_start_test1_button);
-        mButtonTest2 = findViewById(R.id.biometric_start_test2_button);
-        mButtonTest2.setVisibility(View.INVISIBLE);
+        mButtonTestNoneEnrolled = findViewById(R.id.biometric_start_test_none_enrolled);
+        mButtonTestNotSecured = findViewById(R.id.biometric_start_test_not_secured);
+        mButtonTestAuthenticate = findViewById(R.id.biometric_start_test_authenticate_button);
+        mButtonTestCredential = findViewById(R.id.biometric_start_test_credential_button);
 
         PackageManager pm = getApplicationContext().getPackageManager();
         if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
@@ -120,21 +152,28 @@
                 || pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
             requestPermissions(new String[]{Manifest.permission.USE_BIOMETRIC},
                     BIOMETRIC_PERMISSION_REQUEST_CODE);
-            mButtonTest1.setEnabled(false);
-            mButtonTest1.setOnClickListener((view) -> {
+
+            mButtonTestNotSecured.setEnabled(false);
+            mButtonTestNotSecured.setOnClickListener((view) -> {
+                startTest(TEST_NOT_SECURED);
+            });
+            mButtonTestNoneEnrolled.setOnClickListener((view) -> {
                 startTest(TEST_NONE_ENROLLED);
             });
-            mButtonTest2.setOnClickListener((view) -> {
-                startTest(TEST_ENROLLED);
+            mButtonTestAuthenticate.setOnClickListener((view) -> {
+                startTest(TEST_AUTHENTICATE);
             });
             mButtonEnroll.setOnClickListener((view) -> {
                 final Intent intent = new Intent();
                 intent.setAction(BIOMETRIC_ENROLL);
                 startActivity(intent);
             });
+            mButtonTestCredential.setOnClickListener((view) -> {
+                startTest(TEST_DEVICE_CREDENTIAL);
+            });
         } else {
             // NO biometrics available
-            mButtonTest1.setEnabled(false);
+            mButtonTestNoneEnrolled.setEnabled(false);
             getPassButton().setEnabled(true);
         }
     }
@@ -143,7 +182,7 @@
     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] state) {
         if (requestCode == BIOMETRIC_PERMISSION_REQUEST_CODE &&
                 state[0] == PackageManager.PERMISSION_GRANTED) {
-            mButtonTest1.setEnabled(true);
+            mButtonTestNotSecured.setEnabled(true);
         }
     }
 
@@ -151,17 +190,29 @@
         mCurrentTest = testType;
         int result = mBiometricManager.canAuthenticate();
 
-        if (testType == TEST_NONE_ENROLLED) {
+        if (testType == TEST_NOT_SECURED) {
+            if (mKeyguardManager.isDeviceSecure()) {
+                showToastAndLog("Please remove your pin/pattern/password and try again");
+            } else {
+                showBiometricPrompt(true /* allowCredential */);
+            }
+        } else if (testType == TEST_NONE_ENROLLED) {
             if (result == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
-                mExpectedError = BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS;
-                showBiometricPrompt();
+                showBiometricPrompt(false /* allowCredential */);
             } else {
                 showToastAndLog("Error: " + result + " Please remove all biometrics and try again");
             }
-        } else if (testType == TEST_ENROLLED) {
+        } else if (testType == TEST_DEVICE_CREDENTIAL) {
+            if (!mKeyguardManager.isDeviceSecure()) {
+                showToastAndLog("Please set up a pin, pattern, or password and try again");
+            } else if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
+                showToastAndLog("Error: " + result + " Please remove all biometrics and try again");
+            } else {
+                showBiometricPrompt(true /* allowCredential */);
+            }
+        } else if (testType == TEST_AUTHENTICATE) {
             if (result == BiometricManager.BIOMETRIC_SUCCESS) {
-                mExpectedError = 0;
-                showBiometricPrompt();
+                showBiometricPrompt(false /* allowCredential */);
             } else {
                 showToastAndLog("Error: " + result +
                         " Please ensure at least one biometric is enrolled and try again");
@@ -171,10 +222,14 @@
         }
     }
 
-    private void showBiometricPrompt() {
+    private void showBiometricPrompt(boolean allowCredential) {
         BiometricPrompt.Builder builder = new BiometricPrompt.Builder(getApplicationContext())
-            .setTitle("Please authenticate")
-            .setNegativeButton("Cancel", mExecutor, mBiometricPromptButtonListener);
+            .setTitle("Please authenticate");
+        if (allowCredential) {
+            builder.setAllowDeviceCredential(true);
+        } else {
+            builder.setNegativeButton("Cancel", mExecutor, mBiometricPromptButtonListener);
+        }
         BiometricPrompt bp = builder.build();
         mCancellationSignal = new CancellationSignal();
         bp.authenticate(mCancellationSignal, mExecutor, mAuthenticationCallback);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyChainTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyChainTestActivity.java
index fa88e32..d774823 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyChainTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyChainTestActivity.java
@@ -208,6 +208,11 @@
             logStatus("Got right alias.");
             try {
                 PrivateKey privateKey = KeyChain.getPrivateKey(KeyChainTestActivity.this, alias);
+                if (privateKey == null) {
+                    logStatus("FAILED (key unavailable)");
+                    return;
+                }
+
                 byte[] data = new String("hello").getBytes();
                 Signature sign = Signature.getInstance("SHA256withRSA");
                 sign.initSign(privateKey);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java
index 920119f..2ab8bdb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java
@@ -16,11 +16,8 @@
 
 package com.android.cts.verifier.wifi;
 
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
-import android.net.wifi.SupplicantState;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -40,8 +37,8 @@
     private Thread mThread;
     private HandlerThread mHandlerThread;
     protected Handler mHandler;
-
     protected WifiManager mWifiManager;
+    protected TestUtils mTestUtils;
 
     public BaseTestCase(Context context) {
         mContext = context;
@@ -53,9 +50,10 @@
      */
     protected void setUp() {
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+        mTestUtils = new TestUtils(mContext, mListener);
 
         // Ensure we're not connected to any wifi network before we start the tests.
-        if (isConnected(null, null)) {
+        if (mTestUtils.isConnected(null, null)) {
             mListener.onTestFailed(mContext.getString(
                     R.string.wifi_status_connected_to_other_network));
             throw new IllegalStateException("Should not be connected to any network");
@@ -71,27 +69,6 @@
     }
 
     /**
-     * Checks whether the device is connected.
-     *
-     * @param ssid If ssid is specified, then check where the device is connected to a network
-     *             with the specified SSID.
-     * @param bssid If bssid is specified, then check where the device is connected to a network
-     *             with the specified BSSID.
-     * @return
-     */
-    protected boolean isConnected(@Nullable String ssid, @Nullable String bssid) {
-        WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-        if (wifiInfo == null) {
-            Log.e(TAG, "Failed to get WifiInfo");
-            return false;
-        }
-        if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) return false;
-        if (ssid != null && !wifiInfo.getSSID().equals(ssid)) return false;
-        if (bssid != null && !wifiInfo.getBSSID().equals(bssid)) return false;
-        return true;
-    }
-
-    /**
      * Tear down the test case. Executed after test finishes - whether on success or failure.
      */
     protected void tearDown() {
@@ -147,7 +124,7 @@
                         } catch (Exception e) {
                             Log.e(TAG, "Execute failed", e);
                             mListener.onTestFailed(
-                                    mContext.getString(R.string.aware_unexpected_error));
+                                    mContext.getString(R.string.wifi_unexpected_error));
                         } finally {
                             tearDown();
                         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/TestUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/TestUtils.java
new file mode 100644
index 0000000..2b7b4b1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/TestUtils.java
@@ -0,0 +1,173 @@
+/*
+ * 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.wifi;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.cts.verifier.R;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test utility methods.
+ */
+public class TestUtils {
+    private static final String TAG = "NetworkRequestTestCase";
+    private static final boolean DBG = true;
+    private static final int SCAN_TIMEOUT_MS = 30_000;
+
+    private final Context mContext;
+    protected BaseTestCase.Listener mListener;
+    private final WifiManager mWifiManager;
+
+    public TestUtils(Context context, BaseTestCase.Listener listener) {
+        mContext = context;
+        mListener = listener;
+        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+    }
+
+    private boolean startScanAndWaitForResults() throws InterruptedException {
+        IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        // Scan Results available broadcast receiver.
+        BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (DBG) Log.v(TAG, "Broadcast onReceive " + intent);
+                if (!intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) return;
+                if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) return;
+                if (DBG) Log.v(TAG, "Scan results received");
+                countDownLatch.countDown();
+            }
+        };
+        // Register the receiver for scan results broadcast.
+        mContext.registerReceiver(broadcastReceiver, intentFilter);
+
+        // Start scan.
+        if (DBG) Log.v(TAG, "Starting scan");
+        mListener.onTestMsgReceived(mContext.getString(R.string.wifi_status_initiating_scan));
+        if (!mWifiManager.startScan()) {
+            Log.e(TAG, "Failed to start scan");
+            // Unregister the receiver for scan results broadcast.
+            mContext.unregisterReceiver(broadcastReceiver);
+            return false;
+        }
+        // Wait for scan results.
+        if (DBG) Log.v(TAG, "Wait for scan results");
+        if (!countDownLatch.await(SCAN_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            Log.e(TAG, "No new scan results available");
+            // Unregister the receiver for scan results broadcast.
+            mContext.unregisterReceiver(broadcastReceiver);
+            return false;
+        }
+
+        // Unregister the receiver for scan results broadcast.
+        mContext.unregisterReceiver(broadcastReceiver);
+        return true;
+    }
+
+    // Helper to check if the scan result corresponds to an open network.
+    private static boolean isScanResultForOpenNetwork(@NonNull ScanResult scanResult) {
+        String capabilities = scanResult.capabilities;
+        return !capabilities.contains("PSK") && !capabilities.contains("EAP")
+                && !capabilities.contains("WEP") && !capabilities.contains("SAE")
+                && !capabilities.contains("SUITE-B-192") && !capabilities.contains("OWE");
+    }
+
+    /**
+     * Helper method to start a scan and find any open networks in the scan results returned by the
+     * device.
+     * @return ScanResult instance corresponding to an open network if one exists, null if the
+     * scan failed or if there are no open networks found.
+     */
+    public @Nullable ScanResult startScanAndFindAnyOpenNetworkInResults()
+            throws InterruptedException {
+        // Start scan and wait for new results.
+        if (!startScanAndWaitForResults()) {
+            Log.e(TAG,"Failed to initiate a new scan. Using cached results from device");
+        }
+        // Filter results to find an open network.
+        List<ScanResult> scanResults = mWifiManager.getScanResults();
+        for (ScanResult scanResult : scanResults) {
+            if (!TextUtils.isEmpty(scanResult.SSID)
+                    && !TextUtils.isEmpty(scanResult.BSSID)
+                    && isScanResultForOpenNetwork(scanResult)) {
+                if (DBG) Log.v(TAG, "Found open network " + scanResult);
+                return scanResult;
+            }
+        }
+        Log.e(TAG, "No open networks found in scan results");
+        return null;
+    }
+
+    /**
+     * Helper method to check if a scan result with the specified SSID & BSSID matches the scan
+     * results returned by the device.
+     *
+     * @param ssid SSID of the network.
+     * @param bssid BSSID of network.
+     * @return true if there is a match, false otherwise.
+     */
+    public boolean findNetworkInScanResultsResults(@NonNull String ssid, @NonNull String bssid) {
+        List<ScanResult> scanResults = mWifiManager.getScanResults();
+        for (ScanResult scanResult : scanResults) {
+            if (TextUtils.equals(scanResult.SSID, ssid)
+                    && TextUtils.equals(scanResult.BSSID, bssid)) {
+                if (DBG) Log.v(TAG, "Found network " + scanResult);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether the device is connected.
+     *
+     * @param ssid If ssid is specified, then check where the device is connected to a network
+     *             with the specified SSID.
+     * @param bssid If bssid is specified, then check where the device is connected to a network
+     *             with the specified BSSID.
+     * @return true if the device is connected to a network with the specified params, false
+     * otherwise.
+     */
+    public boolean isConnected(@Nullable String ssid, @Nullable String bssid) {
+        WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+        if (wifiInfo == null) {
+            Log.e(TAG, "Failed to get WifiInfo");
+            return false;
+        }
+        if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) return false;
+        if (ssid != null && !wifiInfo.getSSID().equals(ssid)) return false;
+        if (bssid != null && !wifiInfo.getBSSID().equals(bssid)) return false;
+        return true;
+    }
+
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
index 528f7d6..b27407c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
@@ -21,21 +21,16 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.MacAddress;
 import android.net.Network;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
 import android.net.wifi.ScanResult;
-import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkSpecifier;
 import android.os.PatternMatcher;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
@@ -45,9 +40,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Test case for all {@link NetworkRequest} requests with specifier built using
@@ -60,7 +52,6 @@
     private static final String UNAVAILABLE_SSID = "blahblahblah";
     private static final int NETWORK_REQUEST_TIMEOUT_MS = 30_000;
     private static final int CALLBACK_TIMEOUT_MS = 40_000;
-    private static final int SCAN_TIMEOUT_MS = 30_000;
 
     public static final int NETWORK_SPECIFIER_SPECIFIC_SSID_BSSID = 0;
     public static final int NETWORK_SPECIFIER_PATTERN_SSID_BSSID = 1;
@@ -80,7 +71,6 @@
     private ConnectivityManager mConnectivityManager;
     private NetworkRequest mNetworkRequest;
     private CallbackUtils.NetworkCallback mNetworkCallback;
-    private BroadcastReceiver mBroadcastReceiver;
     private String mFailureReason;
 
     public NetworkRequestTestCase(Context context, @NetworkSpecifierType int networkSpecifierType) {
@@ -107,7 +97,7 @@
             case NETWORK_SPECIFIER_UNAVAILABLE_SSID_BSSID:
                 String ssid = UNAVAILABLE_SSID;
                 MacAddress bssid = MacAddress.createRandomUnicastAddress();
-                if (findNetworkInScanResultsResults(ssid, bssid.toString())) {
+                if (mTestUtils.findNetworkInScanResultsResults(ssid, bssid.toString())) {
                     Log.e(TAG, "The specifiers chosen match a network in scan results."
                             + "Test will fail");
                     return null;
@@ -121,82 +111,6 @@
         return configBuilder.build();
     }
 
-    private boolean startScanAndWaitForResults() throws InterruptedException {
-        IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        // Scan Results available broadcast receiver.
-        mBroadcastReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (DBG) Log.v(TAG, "Broadcast onReceive " + intent);
-                if (!intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) return;
-                if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) return;
-                if (DBG) Log.v(TAG, "Scan results received");
-                countDownLatch.countDown();
-            }
-        };
-        // Register the receiver for scan results broadcast.
-        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
-
-        // Start scan.
-        if (DBG) Log.v(TAG, "Starting scan");
-        mListener.onTestMsgReceived(mContext.getString(R.string.wifi_status_initiating_scan));
-        if (!mWifiManager.startScan()) {
-            Log.e(TAG, "Failed to start scan");
-            setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
-            return false;
-        }
-        // Wait for scan results.
-        if (DBG) Log.v(TAG, "Wait for scan results");
-        if (!countDownLatch.await(SCAN_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-            Log.e(TAG, "No new scan results available");
-            setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
-            return false;
-        }
-        return true;
-    }
-
-    // Helper to check if the scan result corresponds to an open network.
-    private static boolean isScanResultForOpenNetwork(@NonNull ScanResult scanResult) {
-        String capabilities = scanResult.capabilities;
-        return !capabilities.contains("PSK") && !capabilities.contains("EAP")
-                && !capabilities.contains("WEP") && !capabilities.contains("SAE")
-                && !capabilities.contains("SUITE-B-192") && !capabilities.contains("OWE");
-    }
-
-    private @Nullable ScanResult startScanAndFindAnyOpenNetworkInResults()
-            throws InterruptedException {
-        // Start scan and wait for new results.
-        if (!startScanAndWaitForResults()) {
-            return null;
-        }
-        // Filter results to find an open network.
-        List<ScanResult> scanResults = mWifiManager.getScanResults();
-        for (ScanResult scanResult : scanResults) {
-            if (!TextUtils.isEmpty(scanResult.SSID)
-                    && !TextUtils.isEmpty(scanResult.BSSID)
-                    && isScanResultForOpenNetwork(scanResult)) {
-                if (DBG) Log.v(TAG, "Found open network " + scanResult);
-                return scanResult;
-            }
-        }
-        Log.e(TAG, "No open networks found in scan results");
-        setFailureReason(mContext.getString(R.string.wifi_status_open_network_not_found));
-        return null;
-    }
-
-    private boolean findNetworkInScanResultsResults(@NonNull String ssid, @NonNull String bssid)
-            throws InterruptedException {
-        List<ScanResult> scanResults = mWifiManager.getScanResults();
-        for (ScanResult scanResult : scanResults) {
-            if (TextUtils.equals(scanResult.SSID, ssid)
-                    && TextUtils.equals(scanResult.BSSID, bssid)) {
-                if (DBG) Log.v(TAG, "Found network " + scanResult);
-                return true;
-            }
-        }
-        return false;
-    }
 
     private void setFailureReason(String reason) {
         synchronized (mLock) {
@@ -208,8 +122,11 @@
     protected boolean executeTest() throws InterruptedException {
         // Step 1: Scan and find any open network around.
         if (DBG) Log.v(TAG, "Scan and find an open network");
-        ScanResult openNetwork = startScanAndFindAnyOpenNetworkInResults();
-        if (openNetwork == null) return false;
+        ScanResult openNetwork = mTestUtils.startScanAndFindAnyOpenNetworkInResults();
+        if (openNetwork == null) {
+            setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
+            return false;
+        }
 
         // Step 2: Create a specifier for the chosen open network depending on the type of test.
         NetworkSpecifier wns = createNetworkSpecifier(openNetwork);
@@ -287,9 +204,6 @@
 
     @Override
     protected void tearDown() {
-        if (mBroadcastReceiver != null) {
-            mContext.unregisterReceiver(mBroadcastReceiver);
-        }
         if (mNetworkCallback != null) {
             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
index 4d0cbc5..f8cf306 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
@@ -20,7 +20,6 @@
 import static android.net.wifi.WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -32,7 +31,6 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkSuggestion;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
@@ -54,7 +52,6 @@
     private static final boolean DBG = true;
 
     private static final int CALLBACK_TIMEOUT_MS = 40_000;
-    private static final int SCAN_TIMEOUT_MS = 30_000;
 
     private final Object mLock = new Object();
     private final List<WifiNetworkSuggestion> mNetworkSuggestions = new ArrayList<>();
@@ -88,73 +85,6 @@
         return builder.build();
     }
 
-    private boolean startScanAndWaitForResults() throws InterruptedException {
-        IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        // Scan Results available broadcast receiver.
-        mBroadcastReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (DBG) Log.v(TAG, "Broadcast onReceive " + intent);
-                if (!intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) return;
-                if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) return;
-                if (DBG) Log.v(TAG, "Scan results received");
-                countDownLatch.countDown();
-            }
-        };
-        // Register the receiver for scan results broadcast.
-        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
-
-        // Start scan.
-        if (DBG) Log.v(TAG, "Starting scan");
-        mListener.onTestMsgReceived(mContext.getString(R.string.wifi_status_initiating_scan));
-        if (!mWifiManager.startScan()) {
-            Log.e(TAG, "Failed to start scan");
-            setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
-            return false;
-        }
-        // Wait for scan results.
-        if (DBG) Log.v(TAG, "Wait for scan results");
-        if (!countDownLatch.await(SCAN_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-            Log.e(TAG, "No new scan results available");
-            setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
-            return false;
-        }
-        // Unregister the scan receiver.
-        mContext.unregisterReceiver(mBroadcastReceiver);
-        mBroadcastReceiver = null;
-        return true;
-    }
-
-    // Helper to check if the scan result corresponds to an open network.
-    private static boolean isScanResultForOpenNetwork(@NonNull ScanResult scanResult) {
-        String capabilities = scanResult.capabilities;
-        return !capabilities.contains("PSK") && !capabilities.contains("EAP")
-                && !capabilities.contains("WEP") && !capabilities.contains("SAE")
-                && !capabilities.contains("SUITE-B-192") && !capabilities.contains("OWE");
-    }
-
-    private @Nullable ScanResult startScanAndFindAnyOpenNetworkInResults()
-            throws InterruptedException {
-        // Start scan and wait for new results.
-        if (!startScanAndWaitForResults()) {
-            return null;
-        }
-        // Filter results to find an open network.
-        List<ScanResult> scanResults = mWifiManager.getScanResults();
-        for (ScanResult scanResult : scanResults) {
-            if (!TextUtils.isEmpty(scanResult.SSID)
-                    && !TextUtils.isEmpty(scanResult.BSSID)
-                    && isScanResultForOpenNetwork(scanResult)) {
-                if (DBG) Log.v(TAG, "Found open network " + scanResult);
-                return scanResult;
-            }
-        }
-        Log.e(TAG, "No open networks found in scan results");
-        setFailureReason(mContext.getString(R.string.wifi_status_open_network_not_found));
-        return null;
-    }
-
     private void setFailureReason(String reason) {
         synchronized (mLock) {
             mFailureReason = reason;
@@ -165,8 +95,11 @@
     protected boolean executeTest() throws InterruptedException {
         // Step 1: Scan and find any open network around.
         if (DBG) Log.v(TAG, "Scan and find an open network");
-        ScanResult openNetwork = startScanAndFindAnyOpenNetworkInResults();
-        if (openNetwork == null) return false;
+        ScanResult openNetwork = mTestUtils.startScanAndFindAnyOpenNetworkInResults();
+        if (openNetwork == null) {
+            setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
+            return false;
+        }
 
         // Step 1.a (Optional): Register for the post connection broadcast.
         final CountDownLatch countDownLatchForPostConnectionBcast = new CountDownLatch(1);
@@ -225,7 +158,7 @@
 
         // Step 6: Ensure that we connected to the suggested network (optionally, the correct
         // BSSID).
-        if (!isConnected("\"" + openNetwork.SSID + "\"",
+        if (!mTestUtils.isConnected("\"" + openNetwork.SSID + "\"",
                 // TODO: This might fail if there are other BSSID's for the same network & the
                 //  device decided to connect/roam to a different BSSID. We don't turn off roaming
                 //  for suggestions.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
index b1bd228..68c741e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
@@ -124,6 +124,7 @@
      */
     public static class NetworkCb extends ConnectivityManager.NetworkCallback {
         private CountDownLatch mBlocker = new CountDownLatch(1);
+        private Network mNetwork = null;
         private NetworkCapabilities mNetworkCapabilities = null;
 
         @Override
@@ -135,18 +136,20 @@
         @Override
         public void onCapabilitiesChanged(Network network,
                 NetworkCapabilities networkCapabilities) {
+            mNetwork = network;
             mNetworkCapabilities = networkCapabilities;
             mBlocker.countDown();
         }
 
         /**
-         * Wait (blocks) for Available or Unavailable callbacks - or timesout.
+         * Wait (blocks) for Capabilities Changed callback - or timesout.
          *
-         * @return true if Available, false otherwise (Unavailable or timeout).
+         * @return Network + NetworkCapabilities (pair) if occurred, null otherwise.
          */
-        public NetworkCapabilities waitForNetwork() throws InterruptedException {
+        public Pair<Network, NetworkCapabilities> waitForNetworkCapabilities()
+                throws InterruptedException {
             if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
-                return mNetworkCapabilities;
+                return Pair.create(mNetwork, mNetworkCapabilities);
             }
             return null;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
index 2f9bf4c..c5175c4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
@@ -20,13 +20,23 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.wifi.aware.WifiAwareManager;
+import android.net.wifi.aware.WifiAwareNetworkInfo;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.wifiaware.CallbackUtils;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Inet6Address;
+import java.net.ServerSocket;
+import java.net.Socket;
 import java.util.Arrays;
 
 /**
@@ -44,7 +54,9 @@
  * 5. Wait for rx message
  * 6. Request network
  *    Wait for network
- * 7. Destroy session
+ * 7. Create socket and bind to server
+ * 8. Send/receive data to validate connection
+ * 9. Destroy session
  *
  * Publish test sequence:
  * 1. Attach
@@ -52,11 +64,13 @@
  * 2. Publish
  *    wait for results (publish session)
  * 3. Wait for rx message
- * 4. Request network
- * 5. Send message
+ * 4. Start a ServerSocket
+ * 5. Request network
+ * 6. Send message
  *    Wait for success
- * 6. Wait for network
- * 7. Destroy session
+ * 7. Wait for network
+ * 8. Receive/Send data to validate connection
+ * 9. Destroy session
  */
 public class DataPathInBandTestCase extends DiscoveryBaseTestCase {
     private static final String TAG = "DataPathInBandTestCase";
@@ -65,8 +79,14 @@
     private static final byte[] MSG_PUB_TO_SUB = "Ready".getBytes();
     private static final String PASSPHRASE = "Some super secret password";
 
+    private static final byte[] MSG_CLIENT_TO_SERVER = "GET SOME BYTES".getBytes();
+    private static final byte[] MSG_SERVER_TO_CLIENT = "PUT SOME OTHER BYTES".getBytes();
+
     private boolean mIsSecurityOpen;
     private boolean mIsPublish;
+    private Thread mClientServerThread;
+    private ConnectivityManager mCm;
+    private CallbackUtils.NetworkCb mNetworkCb;
 
     public DataPathInBandTestCase(Context context, boolean isSecurityOpen, boolean isPublish,
             boolean isUnsolicited) {
@@ -84,6 +104,10 @@
                             + ", mIsUnsolicited=" + mIsUnsolicited);
         }
 
+        mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mClientServerThread = null;
+        mNetworkCb = null;
+
         boolean success;
         if (mIsPublish) {
             success = executeTestPublisher();
@@ -102,6 +126,18 @@
         return true;
     }
 
+    @Override
+    protected void tearDown() {
+        if (mClientServerThread != null) {
+            mClientServerThread.interrupt();
+        }
+        if (mNetworkCb != null) {
+            mCm.unregisterNetworkCallback(mNetworkCb);
+        }
+        super.tearDown();
+    }
+
+
     private boolean executeTestSubscriber() throws InterruptedException {
         if (DBG) Log.d(TAG, "executeTestSubscriber");
         if (!executeSubscribe()) {
@@ -129,33 +165,118 @@
         }
 
         // 6. request network
-        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
+        WifiAwareManager.NetworkSpecifierBuilder nsBuilder =
+                new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+                        mWifiAwareDiscoverySession).setPeerHandle(mPeerHandle);
+        if (!mIsSecurityOpen) {
+            nsBuilder.setPskPassphrase(PASSPHRASE);
+        }
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
-                mIsSecurityOpen ? mWifiAwareDiscoverySession.createNetworkSpecifierOpen(mPeerHandle)
-                        : mWifiAwareDiscoverySession.createNetworkSpecifierPassphrase(mPeerHandle,
-                                PASSPHRASE)).build();
-        CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
-        cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
+                nsBuilder.build()).build();
+        mNetworkCb = new CallbackUtils.NetworkCb();
+        mCm.requestNetwork(nr, mNetworkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(
                 mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestSubscriber: requested network");
-        NetworkCapabilities nc = networkCb.waitForNetwork();
-        cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+
+        // 7. wait for network
+        Pair<Network, NetworkCapabilities> info = mNetworkCb.waitForNetworkCapabilities();
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
-            Log.e(TAG, "executeTestSubscriber: network request rejected - ON_UNAVAILABLE");
+            Log.e(TAG, "executeTestSubscriber: network request rejected or timed-out");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.first == null || info.second == null) {
+            setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+            Log.e(TAG, "executeTestSubscriber: received a null Network or NetworkCapabilities!?");
+            return false;
+        }
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
         }
+
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
         if (DBG) Log.d(TAG, "executeTestSubscriber: network request granted - AVAILABLE");
 
+        if (!mIsSecurityOpen) {
+            if (!(info.second.getTransportInfo() instanceof WifiAwareNetworkInfo)) {
+                setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+                Log.e(TAG, "executeTestSubscriber: did not get WifiAwareNetworkInfo from peer!?");
+                return false;
+            }
+            WifiAwareNetworkInfo peerAwareInfo =
+                    (WifiAwareNetworkInfo) info.second.getTransportInfo();
+            Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr();
+            int peerPort = peerAwareInfo.getPort();
+            int peerTransportProtocol = peerAwareInfo.getTransportProtocol();
+            mListener.onTestMsgReceived(
+                    mContext.getString(R.string.aware_status_socket_server_info_rx,
+                            peerIpv6.toString(),
+                            peerPort));
+            if (DBG) {
+                Log.d(TAG,
+                        "executeTestPublisher: rx peer info IPv6=" + peerIpv6 + ", port=" + peerPort
+                                + ", transportProtocol=" + peerTransportProtocol);
+            }
+            if (peerTransportProtocol != 6) { // 6 == TCP: hard coded at peer
+                setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+                Log.e(TAG, "executeTestSubscriber: Got incorrect transport protocol from peer");
+                return false;
+            }
+            if (peerPort <= 0) {
+                setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+                Log.e(TAG, "executeTestSubscriber: Got invalid port from peer (<=0)");
+                return false;
+            }
+
+            // 8. send/receive - can happen inline here - no need for another thread
+            String currentMethod = "";
+            try {
+                currentMethod = "createSocket";
+                Socket socket = info.first.getSocketFactory().createSocket(peerIpv6, peerPort);
+
+                // simple interaction: write X bytes, read Y bytes
+                currentMethod = "getOutputStream()";
+                OutputStream os = socket.getOutputStream();
+                currentMethod = "write()";
+                os.write(MSG_CLIENT_TO_SERVER, 0, MSG_CLIENT_TO_SERVER.length);
+
+                byte[] buffer = new byte[1024];
+                currentMethod = "getInputStream()";
+                InputStream is = socket.getInputStream();
+                currentMethod = "read()";
+                int numBytes = is.read(buffer, 0, MSG_SERVER_TO_CLIENT.length);
+
+                mListener.onTestMsgReceived(
+                        mContext.getString(R.string.aware_status_socket_server_message_from_peer,
+                                new String(buffer, 0, numBytes)));
+
+                if (numBytes != MSG_SERVER_TO_CLIENT.length) {
+                    setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                    Log.e(TAG,
+                            "executeTestSubscriber: didn't read expected number of bytes - only "
+                                    + "got -- " + numBytes);
+                    return false;
+                }
+                if (!Arrays.equals(MSG_SERVER_TO_CLIENT,
+                        Arrays.copyOf(buffer, MSG_SERVER_TO_CLIENT.length))) {
+                    setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                    Log.e(TAG, "executeTestSubscriber: did not get expected message from server.");
+                    return false;
+                }
+
+                currentMethod = "close()";
+                os.close();
+            } catch (IOException e) {
+                setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                Log.e(TAG, "executeTestSubscriber: failure while executing " + currentMethod);
+                return false;
+            }
+        }
+
         return true;
     }
 
@@ -165,21 +286,90 @@
             return false;
         }
 
-        // 4. Request network
-        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
+        // 4. create a ServerSocket
+        int port = 0;
+        if (!mIsSecurityOpen) {
+            ServerSocket server;
+            try {
+                server = new ServerSocket(0);
+            } catch (IOException e) {
+                setFailureReason(
+                        mContext.getString(R.string.aware_status_socket_failure));
+                Log.e(TAG, "executeTestPublisher: failure creating a ServerSocket -- " + e);
+                return false;
+            }
+            port = server.getLocalPort();
+            mListener.onTestMsgReceived(
+                    mContext.getString(R.string.aware_status_socket_server_socket_started, port));
+            if (DBG) Log.d(TAG, "executeTestPublisher: server socket started on port=" + port);
+
+            // accept connections on the server socket - has to be done in a separate thread!
+            mClientServerThread = new Thread(() -> {
+                String currentMethod = "";
+
+                try {
+                    currentMethod = "accept()";
+                    Socket socket = server.accept();
+                    currentMethod = "getInputStream()";
+                    InputStream is = socket.getInputStream();
+
+                    // simple interaction: read X bytes, write Y bytes
+                    byte[] buffer = new byte[1024];
+                    currentMethod = "read()";
+                    int numBytes = is.read(buffer, 0, MSG_CLIENT_TO_SERVER.length);
+
+                    mListener.onTestMsgReceived(mContext.getString(
+                            R.string.aware_status_socket_server_message_from_peer,
+                            new String(buffer, 0, numBytes)));
+
+                    if (numBytes != MSG_CLIENT_TO_SERVER.length) {
+                        setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                        Log.e(TAG,
+                                "executeTestPublisher: didn't read expected number of bytes - only "
+                                        + "got -- " + numBytes);
+                        return;
+                    }
+                    if (!Arrays.equals(MSG_CLIENT_TO_SERVER,
+                            Arrays.copyOf(buffer, MSG_CLIENT_TO_SERVER.length))) {
+                        setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                        Log.e(TAG,
+                                "executeTestPublisher: did not get expected message from client.");
+                        return;
+                    }
+
+                    currentMethod = "getOutputStream()";
+                    OutputStream os = socket.getOutputStream();
+                    currentMethod = "write()";
+                    os.write(MSG_SERVER_TO_CLIENT, 0, MSG_SERVER_TO_CLIENT.length);
+                    currentMethod = "close()";
+                    os.close();
+                } catch (IOException e) {
+                    setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                    Log.e(TAG, "executeTestPublisher: failure while executing " + currentMethod);
+                    return;
+                }
+            });
+            mClientServerThread.start();
+        }
+
+        // 5. Request network
+        WifiAwareManager.NetworkSpecifierBuilder nsBuilder =
+                new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+                        mWifiAwareDiscoverySession).setPeerHandle(mPeerHandle);
+        if (!mIsSecurityOpen) {
+            nsBuilder.setPskPassphrase(PASSPHRASE).setPort(port).setTransportProtocol(
+                    6); // 6 == TCP
+        }
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
-                mIsSecurityOpen ? mWifiAwareDiscoverySession.createNetworkSpecifierOpen(mPeerHandle)
-                        : mWifiAwareDiscoverySession.createNetworkSpecifierPassphrase(mPeerHandle,
-                                PASSPHRASE)).build();
-        CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
-        cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
+                nsBuilder.build()).build();
+        mNetworkCb = new CallbackUtils.NetworkCb();
+        mCm.requestNetwork(nr, mNetworkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(
                 mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestPublisher: requested network");
 
-        // 5. send message & wait for send status
+        // 6. send message & wait for send status
         mWifiAwareDiscoverySession.sendMessage(mPeerHandle, MESSAGE_ID, MSG_PUB_TO_SUB);
         CallbackUtils.DiscoveryCb.CallbackData callbackData = mDiscoveryCb.waitForCallbacks(
                 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
@@ -204,15 +394,19 @@
             return false;
         }
 
-        // 6. wait for network
-        NetworkCapabilities nc = networkCb.waitForNetwork();
-        cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+        // 7. wait for network
+        Pair<Network, NetworkCapabilities> info = mNetworkCb.waitForNetworkCapabilities();
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
             Log.e(TAG, "executeTestPublisher: request network rejected - ON_UNAVAILABLE");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.first == null || info.second == null) {
+            setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+            Log.e(TAG, "executeTestPublisher: received a null Network or NetworkCapabilities!?");
+            return false;
+        }
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
@@ -220,6 +414,18 @@
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
         if (DBG) Log.d(TAG, "executeTestPublisher: network request granted - AVAILABLE");
 
+        // 8. Send/Receive data to validate connection - happens on thread above
+        if (!mIsSecurityOpen) {
+            mClientServerThread.join(CALLBACK_TIMEOUT_SEC * 1000);
+            if (mClientServerThread.isAlive()) {
+                setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                Log.e(TAG,
+                        "executeTestPublisher: failure while waiting for client-server thread to "
+                                + "finish");
+                return false;
+            }
+        }
+
         return true;
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
index be198e1..0d6ca8f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.wifi.aware.DiscoverySession;
@@ -284,14 +285,14 @@
         cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestResponder: requested network");
-        NetworkCapabilities nc = networkCb.waitForNetwork();
+        Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
         cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
             Log.e(TAG, "executeTestResponder: network request rejected - ON_UNAVAILABLE");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
@@ -423,14 +424,14 @@
         cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestInitiator: requested network");
-        NetworkCapabilities nc = networkCb.waitForNetwork();
+        Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
         cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
             Log.e(TAG, "executeTestInitiator: network request rejected - ON_UNAVAILABLE");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
similarity index 100%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivityLauncher.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
similarity index 91%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
index d844894..3e6a02c 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
+++ b/common/device-side/util/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
@@ -25,6 +25,8 @@
 
 /**
  * Helper used to launch an activity and watch for its lifecycle events.
+ *
+ * @param <A> activity type
  */
 public final class ActivityLauncher<A extends Activity> {
 
@@ -39,11 +41,17 @@
         mLaunchIntent = new Intent(context, activityClass);
     }
 
+    /**
+     * Gets a watcher for the activity lifecycle events.
+     */
     @NonNull
     public ActivityWatcher getWatcher() {
         return mWatcher;
     }
 
+    /**
+     * Launches the activity.
+     */
     @NonNull
     public A launchActivity() {
         return mActivityTestRule.launchActivity(mLaunchIntent);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/DoubleVisitor.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/DoubleVisitor.java
similarity index 100%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/DoubleVisitor.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/DoubleVisitor.java
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/Visitor.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/Visitor.java
similarity index 100%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/Visitor.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/Visitor.java
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
index bf5dc39..7500050 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
@@ -54,6 +54,8 @@
 
     @Override
     protected void tearDown() throws Exception {
+        Log.v(TAG, getClass().getSimpleName() + ".tearDown(): hasFeature=" + mHasFeature
+                + " receiver=" + mActivityDoneReceiver);
         if (mHasFeature && mActivityDoneReceiver != null) {
             try {
                 mContext.unregisterReceiver(mActivityDoneReceiver);
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
deleted file mode 100644
index d12caa8..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
+++ /dev/null
@@ -1,54 +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.
- */
-package com.android.compatibility.common.util;
-
-import org.junit.Before;
-
-/**
- *  Device-side base class for tests leveraging the Business Logic service for rules that are
- *  conditionally added based on the device characteristics.
- */
-public class BusinessLogicConditionalTestCase extends BusinessLogicTestCase {
-
-    @Override
-    @Before
-    public void handleBusinessLogic() {
-        super.loadBusinessLogic();
-        ensureAuthenticated();
-        super.executeBusinessLogic();
-    }
-
-    protected void ensureAuthenticated() {
-        if (!mCanReadBusinessLogic) {
-            // super class handles the condition that the service is unavailable.
-            return;
-        }
-
-        if (!mBusinessLogic.mConditionalTestsEnabled) {
-            skipTest("Execution of device specific tests is not enabled. "
-                    + "Enable with '--conditional-business-logic-tests-enabled'");
-        }
-
-        if (mBusinessLogic.isAuthorized()) {
-            // Run test as normal.
-            return;
-        }
-        String message = mBusinessLogic.getAuthenticationStatusMessage();
-
-        // Fail test since request was not authorized.
-        failTest(String.format("Unable to execute because %s.", message));
-    }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
index 671d33b..29607c3 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
@@ -51,6 +51,7 @@
     @Before
     public void handleBusinessLogic() {
         loadBusinessLogic();
+        ensureAuthenticated();
         executeBusinessLogic();
     }
 
@@ -79,6 +80,27 @@
         }
     }
 
+    protected void ensureAuthenticated() {
+        if (!mCanReadBusinessLogic) {
+            // super class handles the condition that the service is unavailable.
+            return;
+        }
+
+        if (!mBusinessLogic.mConditionalTestsEnabled) {
+            skipTest("Execution of device specific tests is not enabled. "
+                    + "Enable with '--conditional-business-logic-tests-enabled'");
+        }
+
+        if (mBusinessLogic.isAuthorized()) {
+            // Run test as normal.
+            return;
+        }
+        String message = mBusinessLogic.getAuthenticationStatusMessage();
+
+        // Fail test since request was not authorized.
+        failTest(String.format("Unable to execute because %s.", message));
+    }
+
     protected static Instrumentation getInstrumentation() {
         return InstrumentationRegistry.getInstrumentation();
     }
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java b/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
index eee05e2..a4359fd 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
@@ -59,7 +59,10 @@
         };
     }
 
-    private static boolean hasService(@NonNull String service) {
+    /**
+     * Checks if the device has the given service.
+     */
+    public static boolean hasService(@NonNull String service) {
         // TODO: ideally should call SystemServiceManager directly, but we would need to open
         // some @Testing APIs for that.
         String command = "service check " + service;
diff --git a/hostsidetests/abioverride/AndroidTest.xml b/hostsidetests/abioverride/AndroidTest.xml
index 99f731c..be3e818 100644
--- a/hostsidetests/abioverride/AndroidTest.xml
+++ b/hostsidetests/abioverride/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS AbiOverride host test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="webview" />
+    <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="CtsAbiOverrideTestApp.apk" />
diff --git a/hostsidetests/angle/AndroidTest.xml b/hostsidetests/angle/AndroidTest.xml
index c72618a..140da70 100644
--- a/hostsidetests/angle/AndroidTest.xml
+++ b/hostsidetests/angle/AndroidTest.xml
@@ -17,6 +17,8 @@
 <configuration description="Config for CtsAngleIntegrationHostTestCases">
     <option name="test-suite-tag" value="cts" />
     <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" />
     <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/driverTest/Android.mk b/hostsidetests/angle/app/driverTest/Android.mk
index 37a1140..114214e 100644
--- a/hostsidetests/angle/app/driverTest/Android.mk
+++ b/hostsidetests/angle/app/driverTest/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
+LOCAL_COMPATIBILITY_SUITE := cts vts cts_instant
 
 LOCAL_MULTILIB := both
 
diff --git a/hostsidetests/angle/app/driverTest/AndroidManifest.xml b/hostsidetests/angle/app/driverTest/AndroidManifest.xml
index be800a1..28bcb11 100755
--- a/hostsidetests/angle/app/driverTest/AndroidManifest.xml
+++ b/hostsidetests/angle/app/driverTest/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.angleIntegrationTest.driverTest">
+    package="com.android.angleIntegrationTest.driverTest"
+    android:targetSandboxVersion="2">
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/angle/app/driverTestSecondary/Android.mk b/hostsidetests/angle/app/driverTestSecondary/Android.mk
index d361192..760a892 100644
--- a/hostsidetests/angle/app/driverTestSecondary/Android.mk
+++ b/hostsidetests/angle/app/driverTestSecondary/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
+LOCAL_COMPATIBILITY_SUITE := cts vts cts_instant
 
 LOCAL_MULTILIB := both
 
diff --git a/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml b/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml
index bd2739d..5a92e96 100755
--- a/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml
+++ b/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.angleIntegrationTest.driverTestSecondary">
+    package="com.android.angleIntegrationTest.driverTestSecondary"
+    android:targetSandboxVersion="2">
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/appbinding/app/app1/AndroidManifest.xml b/hostsidetests/appbinding/app/app1/AndroidManifest.xml
index b3b55e8..b2c49db 100644
--- a/hostsidetests/appbinding/app/app1/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app1/AndroidManifest.xml
@@ -31,9 +31,9 @@
             android:name=".MyService"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE">
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE">
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app2/AndroidManifest.xml b/hostsidetests/appbinding/app/app2/AndroidManifest.xml
index 7890c6f..7be1599 100644
--- a/hostsidetests/appbinding/app/app2/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app2/AndroidManifest.xml
@@ -31,9 +31,9 @@
             android:name=".MyService2"
             android:exported="false"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app3/AndroidManifest.xml b/hostsidetests/appbinding/app/app3/AndroidManifest.xml
index ec7a4bf..52080ee 100644
--- a/hostsidetests/appbinding/app/app3/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app3/AndroidManifest.xml
@@ -32,7 +32,7 @@
             android:exported="false"
             android:process=":persistent">
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app4/AndroidManifest.xml b/hostsidetests/appbinding/app/app4/AndroidManifest.xml
index 5df5fa8..560c4c1 100644
--- a/hostsidetests/appbinding/app/app4/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app4/AndroidManifest.xml
@@ -31,18 +31,18 @@
             android:name=".MyService"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
         <service
             android:name=".MyService2"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app6/AndroidManifest.xml b/hostsidetests/appbinding/app/app6/AndroidManifest.xml
index abea148..cf704d7 100644
--- a/hostsidetests/appbinding/app/app6/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app6/AndroidManifest.xml
@@ -30,9 +30,9 @@
         <service
             android:name=".MyService2"
             android:exported="false"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/appb/AndroidManifest.xml b/hostsidetests/appbinding/app/appb/AndroidManifest.xml
index 3a1c5d3..e6336a6 100644
--- a/hostsidetests/appbinding/app/appb/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/appb/AndroidManifest.xml
@@ -31,9 +31,9 @@
             android:name="com.android.cts.appbinding.app.MyService"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java b/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
index 5df2fa9..9a569f3 100644
--- a/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
+++ b/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
@@ -15,12 +15,12 @@
  */
 package com.android.cts.appbinding.app;
 
-import android.app.SmsAppService;
+import android.service.carrier.CarrierMessagingClientService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-public class MyService extends SmsAppService {
+public class MyService extends CarrierMessagingClientService {
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
 
@@ -31,6 +31,6 @@
             return;
         }
         writer.print("Package=[" + getPackageName() + "]");
-        writer.println("Class=[" + this.getClass().getName() + "]");
+        writer.println(" Class=[" + this.getClass().getName() + "]");
     }
 }
diff --git a/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java b/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
index dd4c438..5c37e01 100644
--- a/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
+++ b/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
@@ -321,7 +321,7 @@
      */
     public void testSimpleNotBound3() throws Throwable {
         installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
-                "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+                "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
     }
 
     /**
@@ -336,7 +336,7 @@
      */
     public void testSimpleNotBound5() throws Throwable {
         installAndCheckNotBound(APK_5, PACKAGE_A, USER_SYSTEM,
-                "Service with android.telephony.action.SMS_APP_SERVICE not found");
+                "Service with android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE not found");
     }
 
     /**
@@ -355,7 +355,7 @@
         installAndCheckBound(APK_1, PACKAGE_A, SERVICE_1, USER_SYSTEM);
         installAndCheckBound(APK_2, PACKAGE_A, SERVICE_2, USER_SYSTEM);
         installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
-                "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+                "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
         installAndCheckBound(APK_1, PACKAGE_A, SERVICE_1, USER_SYSTEM);
         installAndCheckNotBound(APK_4, PACKAGE_A, USER_SYSTEM, "More than one");
     }
@@ -398,7 +398,7 @@
 
             // Replace the app on the primary user with an invalid one.
             installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
-                    "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+                    "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
 
             // Secondary user should still have a valid connection.
             checkBound(PACKAGE_B, SERVICE_1, userId);
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
deleted file mode 100644
index 1adf0f8..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
+++ /dev/null
@@ -1,36 +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_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitApp
-
-# Tag this module as a cts test artifact
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
deleted file mode 100644
index f37be44..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
+++ /dev/null
@@ -1,35 +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_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureA
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp
-LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
-
-LOCAL_AAPT_FLAGS += --custom-package com.android.cts.classloadersplitapp.feature_a
-LOCAL_AAPT_FLAGS += --package-id 0x80
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
deleted file mode 100644
index 3262e15..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
+++ /dev/null
@@ -1,34 +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_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureB
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp CtsClassloaderSplitAppFeatureA
-LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
-
-LOCAL_AAPT_FLAGS := --custom-package com.android.cts.classloadersplitapp.feature_b
-LOCAL_AAPT_FLAGS += --package-id 0x81
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
index efb4bce..73946e0 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := test_current
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
     android-support-test \
     ub-uiautomator
 
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
index fa1ca7b..7d84684 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.mediastorageapp;
 
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -45,7 +47,6 @@
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.HashSet;
 
@@ -53,11 +54,13 @@
 public class MediaStorageTest {
     private Context mContext;
     private ContentResolver mContentResolver;
+    private int mUserId;
 
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mContentResolver = mContext.getContentResolver();
+        mUserId = mContext.getUserId();
     }
 
     @Test
@@ -65,7 +68,7 @@
         final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
 
-        clearMediaOwner(blue);
+        clearMediaOwner(blue, mUserId);
 
         // Since we have no permissions, we should only be able to see media
         // that we've contributed
@@ -97,7 +100,7 @@
         final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
 
-        clearMediaOwner(blue);
+        clearMediaOwner(blue, mUserId);
 
         // Holding read permission we can see items we don't own
         final HashSet<Long> seen = new HashSet<>();
@@ -126,7 +129,7 @@
         final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
 
-        clearMediaOwner(blue);
+        clearMediaOwner(blue, mUserId);
 
         // Holding read permission we can see items we don't own
         final HashSet<Long> seen = new HashSet<>();
@@ -151,7 +154,7 @@
     @Test
     public void testMediaEscalation() throws Exception {
         final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
-        clearMediaOwner(red);
+        clearMediaOwner(red, mUserId);
 
         // Confirm that we get can take action to get write access
         RecoverableSecurityException exception = null;
@@ -204,12 +207,10 @@
         }
     }
 
-    private static void clearMediaOwner(Uri uri) throws IOException {
-        try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
-                InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
-                        "content update --uri " + uri + " --bind owner_package_name:n:"))) {
-            while (is.read() != -1) {
-            }
-        }
+    private static void clearMediaOwner(Uri uri, int userId) throws IOException {
+        final String cmd = String.format(
+                "content update --uri %s --user %d --bind owner_package_name:n:",
+                uri, userId);
+        runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
deleted file mode 100644
index df12f82..0000000
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
-
-LOCAL_PACKAGE_NAME := CtsUsesLibraryApp
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/atrace/AndroidTest.xml b/hostsidetests/atrace/AndroidTest.xml
index ecaa17a..d616f90 100644
--- a/hostsidetests/atrace/AndroidTest.xml
+++ b/hostsidetests/atrace/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS atrace host test cases">
     <option name="test-suite-tag" value="cts" />
     <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" />
     <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/atrace/AtraceTestApp/AndroidManifest.xml b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
index cb57d14..06253cd 100644
--- a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
+++ b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-       package="com.android.cts.atracetestapp">
+       package="com.android.cts.atracetestapp"
+       android:targetSandboxVersion="2">
     <!--
     A simple app with a tracing section to test that apps tracing signals are
     emitted by atrace.
diff --git a/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java
index 627ff78..b74c7d5 100644
--- a/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java
+++ b/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java
@@ -126,6 +126,7 @@
                 mProfileUserId);
 
         // Force run k/v job.
+        String startLog = mLogcatInspector.mark(TAG);
         int jobId = getJobIdForUser(KEY_VALUE_MIN_JOB_ID, mProfileUserId);
         mBackupUtils.executeShellCommandSync(JOB_SCHEDULER_RUN_COMMAND + " " + jobId);
 
@@ -133,7 +134,7 @@
         mLogcatInspector.assertLogcatContainsInOrder(
                 LOGCAT_FILTER,
                 TIMEOUT_FOR_KEY_VALUE_SECONDS,
-                mLogcatInspector.mark(TAG),
+                startLog,
                 KEY_VALUE_SUCCESS_LOG);
 
         // Check job rescheduled.
@@ -176,6 +177,7 @@
         mBackupUtils.backupNowAndAssertSuccessForUser(PACKAGE_MANAGER_SENTINEL, mProfileUserId);
 
         // Force run full backup job.
+        String startLog = mLogcatInspector.mark(TAG);
         int jobId = getJobIdForUser(FULL_BACKUP_MIN_JOB_ID, mProfileUserId);
         mBackupUtils.executeShellCommandSync(JOB_SCHEDULER_RUN_COMMAND + " " + jobId);
 
@@ -183,7 +185,7 @@
         mLogcatInspector.assertLogcatContainsInOrder(
                 LOGCAT_FILTER,
                 TIMEOUT_FOR_FULL_BACKUP_SECONDS,
-                mLogcatInspector.mark(TAG),
+                startLog,
                 FULL_BACKUP_SUCCESS_LOG);
 
         // Check job rescheduled.
diff --git a/hostsidetests/classloaders/splits/Android.bp b/hostsidetests/classloaders/splits/Android.bp
new file mode 100644
index 0000000..17f02a7
--- /dev/null
+++ b/hostsidetests/classloaders/splits/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.
+
+java_test_host {
+    name: "CtsClassloaderSplitsHostTestCases",
+    defaults: [ "cts_defaults" ],
+    srcs: [ "src/**/*.java" ],
+    libs: [
+        "compatibility-host-util",
+        "cts-tradefed",
+        "tradefed",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    required: [
+        "CtsClassloaderSplitApp",
+        "CtsClassloaderSplitAppFeatureA",
+        "CtsClassloaderSplitAppFeatureB",
+    ],
+}
diff --git a/hostsidetests/classloaders/splits/AndroidTest.xml b/hostsidetests/classloaders/splits/AndroidTest.xml
new file mode 100644
index 0000000..77b5bce
--- /dev/null
+++ b/hostsidetests/classloaders/splits/AndroidTest.xml
@@ -0,0 +1,23 @@
+<?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="Config for the CTS Classloader Splits host tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsClassloaderSplitsHostTestCases.jar" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/classloaders/splits/TEST_MAPPING b/hostsidetests/classloaders/splits/TEST_MAPPING
new file mode 100644
index 0000000..18f00dd
--- /dev/null
+++ b/hostsidetests/classloaders/splits/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsClassloaderSplitsHostTestCases"
+    }
+  ]
+}
diff --git a/hostsidetests/classloaders/splits/apps/Android.bp b/hostsidetests/classloaders/splits/apps/Android.bp
new file mode 100644
index 0000000..ebd9318
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/Android.bp
@@ -0,0 +1,29 @@
+// 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: "CtsClassloaderSplitApp",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "android-support-test",
+        "ctstestrunner",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/AndroidManifest.xml
diff --git a/hostsidetests/classloaders/splits/apps/feature_a/Android.bp b/hostsidetests/classloaders/splits/apps/feature_a/Android.bp
new file mode 100644
index 0000000..0fd7091
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/feature_a/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "CtsClassloaderSplitAppFeatureA",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: [ "src/**/*.java" ],
+    libs: [ "CtsClassloaderSplitApp" ],
+    aaptflags: [
+        "--custom-package",
+        "com.android.cts.classloadersplitapp.feature_a",
+        "--package-id",
+        "0x80",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/feature_a/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/feature_a/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java b/hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
rename to hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java b/hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
rename to hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
diff --git a/hostsidetests/classloaders/splits/apps/feature_b/Android.bp b/hostsidetests/classloaders/splits/apps/feature_b/Android.bp
new file mode 100644
index 0000000..2643840
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/feature_b/Android.bp
@@ -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.
+
+android_test_helper_app {
+    name: "CtsClassloaderSplitAppFeatureB",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: [ "src/**/*.java" ],
+    libs: [
+        "CtsClassloaderSplitApp",
+        "CtsClassloaderSplitAppFeatureA",
+    ],
+    aaptflags: [
+        "--custom-package",
+        "com.android.cts.classloadersplitapp.feature_a",
+        "--package-id",
+        "0x81",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/feature_b/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml b/hostsidetests/classloaders/splits/apps/feature_b/res/values-pl/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/res/values-pl/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml b/hostsidetests/classloaders/splits/apps/feature_b/res/values/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/res/values/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java b/hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
rename to hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java b/hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
rename to hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseReceiver.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/SplitAppTest.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/SplitAppTest.java
diff --git a/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java b/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java
new file mode 100644
index 0000000..f5170e9
--- /dev/null
+++ b/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+package android.classloaders.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
+ *
+ * <code>
+ *     private class InstallMultiple extends BaseInstallMultiple&lt;InstallMultiple&gt; {
+ *         public InstallMultiple() {
+ *             super(getDevice(), null, null);
+ *         }
+ *     }
+ * </code>
+ */
+public class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
+    private final ITestDevice mDevice;
+    private final IBuildInfo mBuild;
+    private final IAbi mAbi;
+
+    private final List<String> mArgs = new ArrayList<>();
+    private final List<File> mApks = new ArrayList<>();
+    private boolean mUseNaturalAbi;
+
+    public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+        mDevice = device;
+        mBuild = buildInfo;
+        mAbi = abi;
+        addArg("-g");
+    }
+
+    T addArg(String arg) {
+        mArgs.add(arg);
+        return (T) this;
+    }
+
+    T addApk(String apk) throws FileNotFoundException {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        mApks.add(buildHelper.getTestFile(apk));
+        return (T) this;
+    }
+
+    T inheritFrom(String packageName) {
+        addArg("-r");
+        addArg("-p " + packageName);
+        return (T) this;
+    }
+
+    T useNaturalAbi() {
+        mUseNaturalAbi = true;
+        return (T) this;
+    }
+
+    T allowTest() {
+        addArg("-t");
+        return (T) this;
+    }
+
+    T locationAuto() {
+        addArg("--install-location 0");
+        return (T) this;
+    }
+
+    T locationInternalOnly() {
+        addArg("--install-location 1");
+        return (T) this;
+    }
+
+    T locationPreferExternal() {
+        addArg("--install-location 2");
+        return (T) this;
+    }
+
+    T forceUuid(String uuid) {
+        addArg("--force-uuid " + uuid);
+        return (T) this;
+    }
+
+    T forUser(int userId) {
+        addArg("--user " + userId);
+        return (T) this;
+    }
+
+    void run() throws DeviceNotAvailableException {
+        run(true, null);
+    }
+
+    void runExpectingFailure() throws DeviceNotAvailableException {
+        run(false, null);
+    }
+
+    void runExpectingFailure(String failure) throws DeviceNotAvailableException {
+        run(false, failure);
+    }
+
+    private void run(boolean expectingSuccess, String failure) throws DeviceNotAvailableException {
+        final ITestDevice device = mDevice;
+
+        // Create an install session
+        final StringBuilder cmd = new StringBuilder();
+        cmd.append("pm install-create");
+        for (String arg : mArgs) {
+            cmd.append(' ').append(arg);
+        }
+        if (!mUseNaturalAbi && mAbi != null) {
+            cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
+        }
+
+        String result = device.executeShellCommand(cmd.toString());
+        TestCase.assertTrue(result, result.startsWith("Success"));
+
+        final int start = result.lastIndexOf("[");
+        final int end = result.lastIndexOf("]");
+        int sessionId = -1;
+        try {
+            if (start != -1 && end != -1 && start < end) {
+                sessionId = Integer.parseInt(result.substring(start + 1, end));
+            }
+        } catch (NumberFormatException e) {
+        }
+        if (sessionId == -1) {
+            throw new IllegalStateException("Failed to create install session: " + result);
+        }
+
+        // Push our files into session. Ideally we'd use stdin streaming,
+        // but ddmlib doesn't support it yet.
+        for (int i = 0; i < mApks.size(); i++) {
+            final File apk = mApks.get(i);
+            final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
+            if (!device.pushFile(apk, remotePath)) {
+                throw new IllegalStateException("Failed to push " + apk);
+            }
+
+            cmd.setLength(0);
+            cmd.append("pm install-write");
+            cmd.append(' ').append(sessionId);
+            cmd.append(' ').append(i + "_" + apk.getName());
+            cmd.append(' ').append(remotePath);
+
+            result = device.executeShellCommand(cmd.toString());
+            TestCase.assertTrue(result, result.startsWith("Success"));
+        }
+
+        // Everything staged; let's pull trigger
+        cmd.setLength(0);
+        cmd.append("pm install-commit");
+        cmd.append(' ').append(sessionId);
+
+        result = device.executeShellCommand(cmd.toString()).trim();
+        if (failure == null) {
+            if (expectingSuccess) {
+                TestCase.assertTrue(result, result.startsWith("Success"));
+            } else {
+                TestCase.assertFalse(result, result.startsWith("Success"));
+            }
+        } else {
+            TestCase.assertTrue(result, result.contains(failure));
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java b/hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
similarity index 89%
rename from hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
rename to hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
index 4e54bc4..1460bfc 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
+++ b/hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
@@ -13,11 +13,12 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
-package android.appsecurity.cts;
+package android.classloaders.cts;
 
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
 import org.junit.After;
 import org.junit.Before;
@@ -25,7 +26,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class ClassloaderSplitsTest extends BaseAppSecurityTest {
+public class ClassloaderSplitsTest extends BaseHostJUnit4Test {
     private static final String PKG = "com.android.cts.classloadersplitapp";
     private static final String TEST_CLASS = PKG + ".SplitAppTest";
 
@@ -47,7 +48,6 @@
 
     @Before
     public void setUp() throws Exception {
-        Utils.prepareSingleUser(getDevice());
         getDevice().uninstallPackage(PKG);
     }
 
@@ -116,4 +116,14 @@
         runDeviceTests(getDevice(), PKG, TEST_CLASS, "testBaseClassLoader");
         runDeviceTests(getDevice(), PKG, TEST_CLASS, "testAllReceivers");
     }
+
+    protected class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            this(false);
+        }
+        public InstallMultiple(boolean instant) {
+            super(getDevice(), getBuild(), getAbi());
+            addArg(instant ? "--instant" : "");
+        }
+    }
 }
diff --git a/hostsidetests/classloaders/useslibrary/Android.bp b/hostsidetests/classloaders/useslibrary/Android.bp
new file mode 100644
index 0000000..603b2ec
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/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.
+
+java_test_host {
+    name: "CtsUsesLibraryHostTestCases",
+    defaults: [ "cts_defaults" ],
+    srcs: [ "src/**/*.java" ],
+    libs: [
+        "compatibility-host-util",
+        "cts-tradefed",
+        "tradefed",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    required: [ "CtsUsesLibraryApp" ],
+}
diff --git a/hostsidetests/classloaders/useslibrary/AndroidTest.xml b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
new file mode 100644
index 0000000..b7796d7
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
@@ -0,0 +1,23 @@
+<?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="Config for the CTS UsesLibrary host tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsUsesLibraryHostTestCases.jar" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/classloaders/useslibrary/TEST_MAPPING b/hostsidetests/classloaders/useslibrary/TEST_MAPPING
new file mode 100644
index 0000000..72ef61b
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsUsesLibraryHostTestCases"
+    }
+  ]
+}
diff --git a/hostsidetests/classloaders/useslibrary/app/Android.bp b/hostsidetests/classloaders/useslibrary/app/Android.bp
new file mode 100644
index 0000000..faf7a22
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/app/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsUsesLibraryApp",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.base.stubs",
+    ],
+    static_libs: [
+        "android-support-test",
+        "ctstestrunner",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml b/hostsidetests/classloaders/useslibrary/app/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml
rename to hostsidetests/classloaders/useslibrary/app/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
similarity index 95%
rename from hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
rename to hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
index 73b820d..7fa8b20 100644
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
+++ b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
@@ -16,11 +16,6 @@
 
 package com.android.cts.useslibrary;
 
-import android.content.pm.PackageManager;
-import android.os.Environment;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
 
 import dalvik.system.BaseDexClassLoader;
diff --git a/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java
new file mode 100644
index 0000000..f5170e9
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+package android.classloaders.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
+ *
+ * <code>
+ *     private class InstallMultiple extends BaseInstallMultiple&lt;InstallMultiple&gt; {
+ *         public InstallMultiple() {
+ *             super(getDevice(), null, null);
+ *         }
+ *     }
+ * </code>
+ */
+public class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
+    private final ITestDevice mDevice;
+    private final IBuildInfo mBuild;
+    private final IAbi mAbi;
+
+    private final List<String> mArgs = new ArrayList<>();
+    private final List<File> mApks = new ArrayList<>();
+    private boolean mUseNaturalAbi;
+
+    public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+        mDevice = device;
+        mBuild = buildInfo;
+        mAbi = abi;
+        addArg("-g");
+    }
+
+    T addArg(String arg) {
+        mArgs.add(arg);
+        return (T) this;
+    }
+
+    T addApk(String apk) throws FileNotFoundException {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        mApks.add(buildHelper.getTestFile(apk));
+        return (T) this;
+    }
+
+    T inheritFrom(String packageName) {
+        addArg("-r");
+        addArg("-p " + packageName);
+        return (T) this;
+    }
+
+    T useNaturalAbi() {
+        mUseNaturalAbi = true;
+        return (T) this;
+    }
+
+    T allowTest() {
+        addArg("-t");
+        return (T) this;
+    }
+
+    T locationAuto() {
+        addArg("--install-location 0");
+        return (T) this;
+    }
+
+    T locationInternalOnly() {
+        addArg("--install-location 1");
+        return (T) this;
+    }
+
+    T locationPreferExternal() {
+        addArg("--install-location 2");
+        return (T) this;
+    }
+
+    T forceUuid(String uuid) {
+        addArg("--force-uuid " + uuid);
+        return (T) this;
+    }
+
+    T forUser(int userId) {
+        addArg("--user " + userId);
+        return (T) this;
+    }
+
+    void run() throws DeviceNotAvailableException {
+        run(true, null);
+    }
+
+    void runExpectingFailure() throws DeviceNotAvailableException {
+        run(false, null);
+    }
+
+    void runExpectingFailure(String failure) throws DeviceNotAvailableException {
+        run(false, failure);
+    }
+
+    private void run(boolean expectingSuccess, String failure) throws DeviceNotAvailableException {
+        final ITestDevice device = mDevice;
+
+        // Create an install session
+        final StringBuilder cmd = new StringBuilder();
+        cmd.append("pm install-create");
+        for (String arg : mArgs) {
+            cmd.append(' ').append(arg);
+        }
+        if (!mUseNaturalAbi && mAbi != null) {
+            cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
+        }
+
+        String result = device.executeShellCommand(cmd.toString());
+        TestCase.assertTrue(result, result.startsWith("Success"));
+
+        final int start = result.lastIndexOf("[");
+        final int end = result.lastIndexOf("]");
+        int sessionId = -1;
+        try {
+            if (start != -1 && end != -1 && start < end) {
+                sessionId = Integer.parseInt(result.substring(start + 1, end));
+            }
+        } catch (NumberFormatException e) {
+        }
+        if (sessionId == -1) {
+            throw new IllegalStateException("Failed to create install session: " + result);
+        }
+
+        // Push our files into session. Ideally we'd use stdin streaming,
+        // but ddmlib doesn't support it yet.
+        for (int i = 0; i < mApks.size(); i++) {
+            final File apk = mApks.get(i);
+            final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
+            if (!device.pushFile(apk, remotePath)) {
+                throw new IllegalStateException("Failed to push " + apk);
+            }
+
+            cmd.setLength(0);
+            cmd.append("pm install-write");
+            cmd.append(' ').append(sessionId);
+            cmd.append(' ').append(i + "_" + apk.getName());
+            cmd.append(' ').append(remotePath);
+
+            result = device.executeShellCommand(cmd.toString());
+            TestCase.assertTrue(result, result.startsWith("Success"));
+        }
+
+        // Everything staged; let's pull trigger
+        cmd.setLength(0);
+        cmd.append("pm install-commit");
+        cmd.append(' ').append(sessionId);
+
+        result = device.executeShellCommand(cmd.toString()).trim();
+        if (failure == null) {
+            if (expectingSuccess) {
+                TestCase.assertTrue(result, result.startsWith("Success"));
+            } else {
+                TestCase.assertFalse(result, result.startsWith("Success"));
+            }
+        } else {
+            TestCase.assertTrue(result, result.contains(failure));
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
similarity index 84%
rename from hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
rename to hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
index 41ce7a1..aecd87b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.appsecurity.cts;
+package android.classloaders.cts;
 
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
 import org.junit.After;
 import org.junit.Before;
@@ -32,7 +33,7 @@
  */
 @AppModeFull(reason = "TODO verify whether or not these should run in instant mode")
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class UsesLibraryHostTest extends BaseAppSecurityTest {
+public class UsesLibraryHostTest extends BaseHostJUnit4Test {
     private static final String PKG = "com.android.cts.useslibrary";
 
     private static final String APK = "CtsUsesLibraryApp.apk";
@@ -79,4 +80,14 @@
         new InstallMultiple(instant).addApk(APK).run();
         Utils.runDeviceTests(getDevice(), PKG, ".UsesLibraryTest", "testDuplicateLibrary");
     }
+
+    protected class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            this(false);
+        }
+        public InstallMultiple(boolean instant) {
+            super(getDevice(), getBuild(), getAbi());
+            addArg(instant ? "--instant" : "");
+        }
+    }
 }
diff --git a/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java
new file mode 100644
index 0000000..48497d8
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+package android.classloaders.cts;
+
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class Utils {
+    public static final int USER_SYSTEM = 0;
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName) throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, null);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, Map<String, String> testArgs)
+                    throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, testArgs);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, int userId) throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, testMethodName, userId, null);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, int userId, Map<String, String> testArgs)
+                    throws DeviceNotAvailableException {
+        // 60 min timeout per test by default
+        runDeviceTests(device, packageName, testClassName, testMethodName, userId, testArgs,
+                60L, TimeUnit.MINUTES);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, int userId, Map<String, String> testArgs, long timeout,
+            TimeUnit unit)
+                    throws DeviceNotAvailableException {
+        if (testClassName != null && testClassName.startsWith(".")) {
+            testClassName = packageName + testClassName;
+        }
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
+                "android.support.test.runner.AndroidJUnitRunner", device.getIDevice());
+        // timeout_msec is the timeout per test for instrumentation
+        testRunner.addInstrumentationArg("timeout_msec", Long.toString(unit.toMillis(timeout)));
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        } else if (testClassName != null) {
+            testRunner.setClassName(testClassName);
+        }
+
+        if (testArgs != null && testArgs.size() > 0) {
+            for (String name : testArgs.keySet()) {
+                final String value = testArgs.get(name);
+                testRunner.addInstrumentationArg(name, value);
+            }
+        }
+        final CollectingTestListener listener = new CollectingTestListener();
+        device.runInstrumentationTestsAsUser(testRunner, userId, listener);
+
+        final TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            throw new AssertionError("Failed to successfully run device tests for "
+                    + result.getName() + ": " + result.getRunFailureMessage());
+        }
+        if (result.getNumTests() == 0) {
+            throw new AssertionError("No tests were run on the device");
+        }
+        if (result.hasFailedTests()) {
+            // build a meaningful error message
+            StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
+            for (Map.Entry<TestDescription, TestResult> resultEntry :
+                result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            throw new AssertionError(errorBuilder.toString());
+        }
+    }
+
+    /**
+     * Prepare and return a single user relevant for testing.
+     */
+    public static int[] prepareSingleUser(ITestDevice device)
+            throws DeviceNotAvailableException {
+        return prepareMultipleUsers(device, 1);
+    }
+
+    /**
+     * Prepare and return two users relevant for testing.
+     */
+    public static int[] prepareMultipleUsers(ITestDevice device)
+            throws DeviceNotAvailableException {
+        return prepareMultipleUsers(device, 2);
+    }
+
+    /**
+     * Prepare and return multiple users relevant for testing.
+     */
+    public static int[] prepareMultipleUsers(ITestDevice device, int maxUsers)
+            throws DeviceNotAvailableException {
+        final int[] userIds = getAllUsers(device);
+        for (int i = 1; i < userIds.length; i++) {
+            if (i < maxUsers) {
+                device.startUser(userIds[i]);
+            } else {
+                device.stopUser(userIds[i]);
+            }
+        }
+        if (userIds.length > maxUsers) {
+            return Arrays.copyOf(userIds, maxUsers);
+        } else {
+            return userIds;
+        }
+    }
+
+    public static int[] getAllUsers(ITestDevice device)
+            throws DeviceNotAvailableException {
+        Integer primary = device.getPrimaryUserId();
+        if (primary == null) {
+            primary = USER_SYSTEM;
+        }
+        int[] users = new int[] { primary };
+        for (Integer user : device.listUsers()) {
+            if ((user != USER_SYSTEM) && (user != primary)) {
+                users = Arrays.copyOf(users, users.length + 1);
+                users[users.length - 1] = user;
+            }
+        }
+        return users;
+    }
+}
diff --git a/hostsidetests/compilation/AndroidTest.xml b/hostsidetests/compilation/AndroidTest.xml
index fe17ac8..d2c6f87 100644
--- a/hostsidetests/compilation/AndroidTest.xml
+++ b/hostsidetests/compilation/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS Compilation Test">
     <option name="test-suite-tag" value="cts" />
     <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" />
     <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/compilation/TEST_MAPPING b/hostsidetests/compilation/TEST_MAPPING
new file mode 100644
index 0000000..cdaa108
--- /dev/null
+++ b/hostsidetests/compilation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsCompilationTestCases"
+    }
+  ]
+}
diff --git a/hostsidetests/compilation/app/AndroidManifest.xml b/hostsidetests/compilation/app/AndroidManifest.xml
index 33fc3ab..cca9341 100755
--- a/hostsidetests/compilation/app/AndroidManifest.xml
+++ b/hostsidetests/compilation/app/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.cts.compilation">
+    package="android.compilation.cts">
     <uses-sdk android:minSdkVersion="23" />
     <application>
         <activity android:name=".CompilationTargetActivity" >
diff --git a/hostsidetests/compilation/app/src/android/cts/compilation/CompilationTargetActivity.java b/hostsidetests/compilation/app/src/android/compilation/cts/CompilationTargetActivity.java
similarity index 99%
rename from hostsidetests/compilation/app/src/android/cts/compilation/CompilationTargetActivity.java
rename to hostsidetests/compilation/app/src/android/compilation/cts/CompilationTargetActivity.java
index 180b4c4..66ff046 100644
--- a/hostsidetests/compilation/app/src/android/cts/compilation/CompilationTargetActivity.java
+++ b/hostsidetests/compilation/app/src/android/compilation/cts/CompilationTargetActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.cts.compilation;
+package android.compilation.cts;
 
 import android.app.Activity;
 import android.os.AsyncTask;
diff --git a/hostsidetests/compilation/assets/CtsCompilationApp.apk b/hostsidetests/compilation/assets/CtsCompilationApp.apk
index 1764915..18c76d3 100644
--- a/hostsidetests/compilation/assets/CtsCompilationApp.apk
+++ b/hostsidetests/compilation/assets/CtsCompilationApp.apk
Binary files differ
diff --git a/hostsidetests/compilation/assets/README.txt b/hostsidetests/compilation/assets/README.txt
index aca7dff..0ce8006 100644
--- a/hostsidetests/compilation/assets/README.txt
+++ b/hostsidetests/compilation/assets/README.txt
@@ -6,6 +6,6 @@
 $ adb install CtsCompilationApp.apk
 
   # Now run the app manually for a couple of minutes, look for the profile:
-$ adb shell ls -l /data/misc/profiles/cur/0/android.cts.compilation/primary.prof
+$ adb shell ls -l /data/misc/profiles/cur/0/android.compilation.cts/primary.prof
   # once the profile appears and is nonempty, grab it:
-$ adb pull /data/misc/profiles/cur/0/android.cts.compilation/primary.prof ./
+$ adb pull /data/misc/profiles/cur/0/android.compilation.cts/primary.prof ./
diff --git a/hostsidetests/compilation/assets/primary.prof.txt b/hostsidetests/compilation/assets/primary.prof.txt
index fd55262..63bbff8 100644
--- a/hostsidetests/compilation/assets/primary.prof.txt
+++ b/hostsidetests/compilation/assets/primary.prof.txt
@@ -1,103 +1,103 @@
-Landroid/cts/compilation/CompilationTargetActivity;
-SHLandroid/cts/compilation/CompilationTargetActivity;->m0()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m1()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m2()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m3()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m4()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m5()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m6()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m7()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m8()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m9()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m10()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m11()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m12()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m13()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m14()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m15()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m16()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m17()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m18()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m19()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m20()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m21()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m22()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m23()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m24()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m25()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m26()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m27()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m28()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m29()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m30()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m31()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m32()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m33()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m34()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m35()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m36()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m37()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m38()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m39()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m40()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m41()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m42()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m43()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m44()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m45()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m46()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m47()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m48()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m49()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m50()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m51()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m52()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m53()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m54()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m55()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m56()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m57()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m58()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m59()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m60()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m61()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m62()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m63()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m64()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m65()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m66()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m67()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m68()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m69()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m70()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m71()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m72()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m73()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m74()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m75()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m76()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m77()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m78()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m79()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m80()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m81()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m82()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m83()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m84()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m85()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m86()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m87()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m88()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m89()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m90()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m91()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m92()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m93()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m94()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m95()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m96()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m97()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m98()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m99()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m100()I
-SHLandroid/cts/compilation/CompilationTargetActivity;->m101()I
\ No newline at end of file
+Landroid/compilation/cts/CompilationTargetActivity;
+SHLandroid/compilation/cts/CompilationTargetActivity;->m0()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m1()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m2()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m3()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m4()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m5()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m6()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m7()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m8()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m9()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m10()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m11()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m12()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m13()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m14()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m15()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m16()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m17()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m18()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m19()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m20()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m21()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m22()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m23()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m24()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m25()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m26()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m27()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m28()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m29()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m30()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m31()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m32()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m33()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m34()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m35()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m36()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m37()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m38()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m39()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m40()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m41()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m42()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m43()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m44()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m45()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m46()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m47()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m48()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m49()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m50()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m51()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m52()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m53()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m54()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m55()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m56()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m57()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m58()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m59()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m60()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m61()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m62()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m63()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m64()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m65()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m66()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m67()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m68()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m69()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m70()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m71()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m72()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m73()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m74()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m75()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m76()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m77()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m78()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m79()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m80()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m81()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m82()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m83()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m84()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m85()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m86()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m87()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m88()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m89()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m90()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m91()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m92()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m93()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m94()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m95()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m96()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m97()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m98()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m99()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m100()I
+SHLandroid/compilation/cts/CompilationTargetActivity;->m101()I
\ No newline at end of file
diff --git a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java b/hostsidetests/compilation/src/android/compilation/cts/AdbRootDependentCompilationTest.java
similarity index 98%
rename from hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
rename to hostsidetests/compilation/src/android/compilation/cts/AdbRootDependentCompilationTest.java
index 0f0e13b..d371a08 100644
--- a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
+++ b/hostsidetests/compilation/src/android/compilation/cts/AdbRootDependentCompilationTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.cts.compilation;
+package android.compilation.cts;
 
 import com.google.common.io.ByteStreams;
 import com.google.common.io.Files;
@@ -51,7 +51,7 @@
  * </ul>
  */
 public class AdbRootDependentCompilationTest extends DeviceTestCase {
-    private static final String APPLICATION_PACKAGE = "android.cts.compilation";
+    private static final String APPLICATION_PACKAGE = "android.compilation.cts";
 
     enum ProfileLocation {
         CUR("/data/misc/profiles/cur/0/" + APPLICATION_PACKAGE),
@@ -320,13 +320,13 @@
      * been created by the compiler.
      */
     private String getOdexFilePath() throws DeviceNotAvailableException {
-        // Something like "package:/data/app/android.cts.compilation-1/base.apk"
+        // Something like "package:/data/app/android.compilation.cts-1/base.apk"
         String pathSpec = executeSuShellAdbCommand(1, "pm", "path", APPLICATION_PACKAGE)[0];
         Matcher matcher = Pattern.compile("^package:(.+/)base\\.apk$").matcher(pathSpec);
         boolean found = matcher.find();
         assertTrue("Malformed spec: " + pathSpec, found);
         String apkDir = matcher.group(1);
-        // E.g. /data/app/android.cts.compilation-1/oat/arm64/base.odex
+        // E.g. /data/app/android.compilation.cts-1/oat/arm64/base.odex
         String result = executeSuShellAdbCommand(1, "find", apkDir, "-name", "base.odex")[0];
         assertTrue("odex file not found: " + result, doesFileExist(result));
         return result;
@@ -405,7 +405,7 @@
 
         // For directories, it will print many outputs. Filter to first line which contains '.'
         // The target line will look like
-        //      "u:object_r:shell_data_file:s0 /data/local/tmp/android.cts.compilation.primary.prof"
+        //      "u:object_r:shell_data_file:s0 /data/local/tmp/android.compilation.cts.primary.prof"
         // Remove the second word to only return "u:object_r:shell_data_file:s0".
 
         return res[0].replaceAll("\\s+.*","");  // remove everything following the first whitespace
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/DirectDelegatedCertInstallerTest.java b/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/DirectDelegatedCertInstallerTest.java
index 59d386e..97ff034 100644
--- a/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/DirectDelegatedCertInstallerTest.java
+++ b/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/DirectDelegatedCertInstallerTest.java
@@ -184,8 +184,7 @@
 
         // Test cleaning up the key.
         assertThat(mDpm.removeKeyPair(null, alias)).isTrue();
-        assertThrows(
-                KeyChainException.class, () -> KeyChain.getPrivateKey(getContext(), alias));
+        assertThat(KeyChain.getPrivateKey(getContext(), alias)).isNull();
     }
 
     // Test that a key generation request succeeds when device identifiers are not requested.
diff --git a/tests/tests/theme/Android.mk b/hostsidetests/devicepolicy/app/ContentCaptureApp/Android.mk
similarity index 79%
rename from tests/tests/theme/Android.mk
rename to hostsidetests/devicepolicy/app/ContentCaptureApp/Android.mk
index ff8536b..1fb6251 100644
--- a/tests/tests/theme/Android.mk
+++ b/hostsidetests/devicepolicy/app/ContentCaptureApp/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 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,23 +16,22 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsThemeDeviceTestCases
-
 # 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
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
 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_SDK_VERSION := current
+LOCAL_PACKAGE_NAME := CtsDevicePolicyContentCaptureApp
+
+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/ContentCaptureApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ContentCaptureApp/AndroidManifest.xml
new file mode 100644
index 0000000..a0d7b30
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ContentCaptureApp/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?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="com.android.cts.devicepolicy.contentcaptureapp" >
+
+    <application>
+        <activity android:name=".SimpleActivity" android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service
+            android:name=".SimpleContentCaptureService"
+            android:permission="android.permission.BIND_CONTENT_CAPTURE_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.contentcapture.ContentCaptureService" />
+            </intent-filter>
+        </service>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/ContentCaptureApp/src/com/android/cts/devicepolicy/contentcaptureapp/SimpleActivity.java b/hostsidetests/devicepolicy/app/ContentCaptureApp/src/com/android/cts/devicepolicy/contentcaptureapp/SimpleActivity.java
new file mode 100644
index 0000000..5ed3bb2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ContentCaptureApp/src/com/android/cts/devicepolicy/contentcaptureapp/SimpleActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.devicepolicy.contentcaptureapp;
+
+import android.app.Activity;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureManager;
+
+public class SimpleActivity extends Activity {
+
+    public static final String TAG = SimpleActivity.class.getSimpleName();
+
+    @Override
+    public void onStart() {
+        Log.d(TAG, "onStart(): userId=" + android.os.Process.myUserHandle().getIdentifier());
+        super.onStart();
+        final ContentCaptureManager mgr = getSystemService(ContentCaptureManager.class);
+        if (mgr == null) {
+            Log.e(TAG, "no manager");
+            return;
+        }
+        final boolean enabled = mgr.isContentCaptureEnabled();
+        Log.v(TAG, "enabled: " + enabled);
+        setResult(enabled ? 1 : 0);
+        finish();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ContentCaptureApp/src/com/android/cts/devicepolicy/contentcaptureapp/SimpleContentCaptureService.java b/hostsidetests/devicepolicy/app/ContentCaptureApp/src/com/android/cts/devicepolicy/contentcaptureapp/SimpleContentCaptureService.java
new file mode 100644
index 0000000..8d11d6a
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ContentCaptureApp/src/com/android/cts/devicepolicy/contentcaptureapp/SimpleContentCaptureService.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 com.android.cts.devicepolicy.contentcaptureapp;
+
+import android.service.contentcapture.ContentCaptureService;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureContext;
+import android.view.contentcapture.ContentCaptureSessionId;
+
+public class SimpleContentCaptureService extends ContentCaptureService {
+
+    private static final String TAG = SimpleContentCaptureService.class.getSimpleName();
+
+    @Override
+    public void onConnected() {
+        Log.d(TAG, "onConnected()");
+    }
+
+    @Override
+    public void onDisconnected() {
+        Log.d(TAG, "onDisconnected()");
+    }
+
+    @Override
+    public void onCreateContentCaptureSession(ContentCaptureContext context,
+            ContentCaptureSessionId sessionId) {
+        Log.d(TAG, "onCreateContentCaptureSession(): " + sessionId);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
index 5419611..7eb7546 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -74,6 +74,8 @@
 
         <activity android:name="com.android.cts.deviceandprofileowner.AutofillActivity"/>
 
+        <activity android:name="com.android.cts.deviceandprofileowner.ContentCaptureActivity"/>
+
         <activity android:name=".PrintActivity"/>
 
         <activity
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ContentCaptureActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ContentCaptureActivity.java
new file mode 100644
index 0000000..c2f27b7
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ContentCaptureActivity.java
@@ -0,0 +1,65 @@
+/*
+ * 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.deviceandprofileowner;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Wrapper class used to call the activity in the non-test APK and wait for its result.
+ */
+public class ContentCaptureActivity extends Activity {
+
+    public static final String CONTENT_CAPTURE_PACKAGE_NAME =
+            "com.android.cts.devicepolicy.contentcaptureapp";
+    public static final String CONTENT_CAPTURE_ACTIVITY_NAME = CONTENT_CAPTURE_PACKAGE_NAME
+            + ".SimpleActivity";
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+    private boolean mEnabled;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Intent launchIntent = new Intent();
+        launchIntent.setComponent(
+                new ComponentName(CONTENT_CAPTURE_PACKAGE_NAME, CONTENT_CAPTURE_ACTIVITY_NAME));
+        startActivityForResult(launchIntent, 42);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        mEnabled = resultCode == 1;
+        mLatch.countDown();
+    }
+
+    public boolean isContentCaptureEnabled() throws InterruptedException {
+        final boolean called = mLatch.await(2, TimeUnit.SECONDS);
+        if (!called) {
+            throw new IllegalStateException(CONTENT_CAPTURE_PACKAGE_NAME
+                    + " didn't finish in 2 seconds");
+        }
+        finish();
+        return mEnabled;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ContentCaptureRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ContentCaptureRestrictionsTest.java
new file mode 100644
index 0000000..95b953b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ContentCaptureRestrictionsTest.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 com.android.cts.deviceandprofileowner;
+
+import static android.os.UserManager.DISALLOW_CONTENT_CAPTURE;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+
+import static com.android.cts.deviceandprofileowner.ContentCaptureActivity.CONTENT_CAPTURE_ACTIVITY_NAME;
+import static com.android.cts.deviceandprofileowner.ContentCaptureActivity.CONTENT_CAPTURE_PACKAGE_NAME;
+
+import android.content.Intent;
+
+public class ContentCaptureRestrictionsTest extends BaseDeviceAdminTest {
+
+    // TODO(b/123540602): use @TestAPI to get max duration constant from ContentCaptureManager
+    private static final int MAX_TIME_TEMPORARY_SERVICE_CAN_BE_SET= 12000;
+
+    private static final int SLEEP_TIME_WAITING_FOR_SERVICE_CONNECTION_MS = 100;
+
+    private static final String SERVICE_NAME =
+            "com.android.cts.devicepolicy.contentcapture/.SimpleContentCaptureService";
+
+    int mUserId;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mUserId = getInstrumentation().getContext().getUserId();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            disableService();
+        } finally {
+            mDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                    DISALLOW_CONTENT_CAPTURE);
+        }
+        super.tearDown();
+    }
+
+    public void testDisallowContentCapture_allowed() throws Exception {
+        enableService();
+
+        final boolean enabledBefore = launchActivityAndGetEnabled();
+        assertTrue(enabledBefore);
+
+        mDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT, DISALLOW_CONTENT_CAPTURE);
+
+        // Must try a couple times because it will be disabled asynchronously.
+        for (int i = 1; i <= 5; i++) {
+            final boolean disabledAfter = !launchActivityAndGetEnabled();
+            if (disabledAfter) {
+                return;
+            }
+            Thread.sleep(100);
+        }
+        fail("Not disabled after 2.5s");
+    }
+
+    private boolean launchActivityAndGetEnabled() throws Exception {
+        final Intent launchIntent = new Intent();
+        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        launchIntent.setClassName(CONTENT_CAPTURE_PACKAGE_NAME, CONTENT_CAPTURE_ACTIVITY_NAME);
+        final ContentCaptureActivity activity = launchActivity(
+                "com.android.cts.deviceandprofileowner", ContentCaptureActivity.class, null);
+        return activity.isContentCaptureEnabled();
+    }
+
+    private void enableService() throws Exception {
+        runShellCommand("cmd content_capture set temporary-service %d %s %d", mUserId,
+                SERVICE_NAME, MAX_TIME_TEMPORARY_SERVICE_CAN_BE_SET);
+        // TODO: ideally it should wait until the service's onConnected() is called, but that
+        // would be too complicated
+        Thread.sleep(SLEEP_TIME_WAITING_FOR_SERVICE_CONNECTION_MS);
+    }
+
+    private void disableService() {
+        runShellCommand("cmd content_capture set temporary-service %d", mUserId);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
index 189c619..c6f2f7b 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
@@ -95,6 +95,11 @@
                 UserManager.DISALLOW_AUTOFILL);
         mDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT,
                 UserManager.DISALLOW_AUTOFILL);
+
+        mDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                UserManager.DISALLOW_CONTENT_CAPTURE);
+        mDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                UserManager.DISALLOW_CONTENT_CAPTURE);
     }
 
     public void testSetSecureSettingLogged()
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
index 85b2903..302523b 100755
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
@@ -715,15 +715,9 @@
         }
     }
 
-    private void assertGranted(String alias, boolean expected) throws InterruptedException {
-        boolean granted = false;
-        try {
-            granted = (KeyChain.getPrivateKey(mActivity, alias) != null);
-        } catch (KeyChainException e) {
-            if (expected) {
-                e.printStackTrace();
-            }
-        }
+    private void assertGranted(String alias, boolean expected)
+            throws InterruptedException, KeyChainException {
+        boolean granted = (KeyChain.getPrivateKey(mActivity, alias) != null);
         assertWithMessage("Grant for alias: \"" + alias + "\"").that(granted).isEqualTo(expected);
     }
 
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
index 0534f2a..63c5380 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
@@ -58,6 +58,7 @@
             UserManager.DISALLOW_SET_USER_ICON,
             UserManager.DISALLOW_BLUETOOTH,
             UserManager.DISALLOW_AUTOFILL,
+            UserManager.DISALLOW_CONTENT_CAPTURE,
             UserManager.DISALLOW_UNIFIED_PASSWORD,
     };
 
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java
index 5c9700e..233a23d 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java
@@ -45,6 +45,7 @@
             UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
             UserManager.DISALLOW_SET_USER_ICON,
             UserManager.DISALLOW_AUTOFILL,
+            UserManager.DISALLOW_CONTENT_CAPTURE,
             UserManager.DISALLOW_UNIFIED_PASSWORD,
     };
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
index 1d6105d..72bebcf 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
@@ -20,6 +20,7 @@
 
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -29,7 +30,9 @@
 import android.support.test.uiautomator.UiDevice;
 import android.util.Log;
 
+import org.junit.After;
 import org.junit.Before;
+import org.junit.After;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -45,6 +48,8 @@
 
     private static final String TAG = LockTaskHostDrivenTest.class.getName();
 
+    private static final int ACTIVITY_RESUMED_TIMEOUT_MILLIS = 20000;  // 20 seconds
+
     private static final String LOCK_TASK_ACTIVITY
             = LockTaskUtilityActivityIfWhitelisted.class.getName();
 
@@ -53,14 +58,45 @@
     private ActivityManager mActivityManager;
     private DevicePolicyManager mDevicePolicyManager;
 
+    private volatile boolean mIsActivityResumed;
+    private final Object mActivityResumedLock = new Object();
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.d(TAG, "onReceive: " + action);
+            if (LockTaskUtilityActivity.RESUME_ACTION.equals(action)) {
+                synchronized (mActivityResumedLock) {
+                    mIsActivityResumed = true;
+                    mActivityResumedLock.notify();
+                }
+            } else if (LockTaskUtilityActivity.PAUSE_ACTION.equals(action)) {
+                synchronized (mActivityResumedLock) {
+                    mIsActivityResumed = false;
+                    mActivityResumedLock.notify();
+                }
+            }
+        }
+    };
+
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getContext();
         mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
         mActivityManager = mContext.getSystemService(ActivityManager.class);
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(LockTaskUtilityActivity.RESUME_ACTION);
+        filter.addAction(LockTaskUtilityActivity.PAUSE_ACTION);
+        mContext.registerReceiver(mReceiver, filter);
     }
 
+    @After
+    public void tearDown() {
+        mContext.unregisterReceiver(mReceiver);
+    }
+  
     @Test
     public void startLockTask() throws Exception {
         Log.d(TAG, "startLockTask on host-driven test (no cleanup)");
@@ -77,6 +113,13 @@
     public void testLockTaskIsActiveAndCantBeInterrupted() throws Exception {
         mUiDevice.waitForIdle();
 
+        // We need to wait until the LockTaskActivity is ready
+        // since com.android.cts.deviceowner can be killed by AMS for reason "start instr".
+        synchronized (mActivityResumedLock) {
+            if (!mIsActivityResumed) {
+                mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+            }
+        }
         checkLockedActivityIsRunning();
 
         mUiDevice.pressBack();
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
index 8e51bc3..3dd79c8 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
@@ -135,4 +135,26 @@
                 DUMMY_PRIVATE_DNS_HOST,
                 DevicePolicyManager.PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING);
     }
+
+    public void testCanSetModeDespiteUserRestriction() {
+        // First set a specific host and assert that applied.
+        callSetGlobalPrivateDnsExpectingResult(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+                VALID_PRIVATE_DNS_HOST,
+                DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS);
+        assertThat(
+                mDevicePolicyManager.getGlobalPrivateDnsMode(getWho())).isEqualTo(
+                PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+
+        // Set a user restriction
+        setUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS, true);
+
+        // Next, set the mode to automatic and confirm that has applied.
+        callSetGlobalPrivateDnsExpectingResult(PRIVATE_DNS_MODE_OPPORTUNISTIC, null,
+                DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS);
+
+        assertThat(
+                mDevicePolicyManager.getGlobalPrivateDnsMode(getWho())).isEqualTo(
+                PRIVATE_DNS_MODE_OPPORTUNISTIC);
+        assertThat(mDevicePolicyManager.getGlobalPrivateDnsHost(getWho())).isNull();
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 260b730..7620734 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -115,6 +115,10 @@
     private static final String AUTOFILL_APP_PKG = "com.android.cts.devicepolicy.autofillapp";
     private static final String AUTOFILL_APP_APK = "CtsDevicePolicyAutofillApp.apk";
 
+    private static final String CONTENT_CAPTURE_APP_PKG =
+            "com.android.cts.devicepolicy.contentcaptureapp";
+    private static final String CONTENT_CAPTURE_APP_APK = "CtsDevicePolicyContentCaptureApp.apk";
+
     protected static final String ASSIST_APP_PKG = "com.android.cts.devicepolicy.assistapp";
     protected static final String ASSIST_APP_APK = "CtsDevicePolicyAssistApp.apk";
 
@@ -855,8 +859,8 @@
         if (!mHasFeature) {
             return;
         }
-        boolean mHasAutofill = hasDeviceFeature("android.software.autofill");
-        if (!mHasAutofill) {
+        boolean hasAutofill = hasDeviceFeature("android.software.autofill");
+        if (!hasAutofill) {
           return;
         }
         installAppAsUser(AUTOFILL_APP_APK, mUserId);
@@ -865,6 +869,35 @@
                 "testDisallowAutofill_allowed");
     }
 
+    // TODO(b/124127364): currently disabled becase ContentCaptureManager.isContentCaptureEnabled()
+    // doesn't return right value when the service is disabled after the activity already launched
+    public void disabledtestDisallowContentCapture_allowed() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        boolean hasContentCapture = hasService("content_capture");
+        if (!hasContentCapture) {
+            return;
+        }
+        installAppAsUser(CONTENT_CAPTURE_APP_APK, mUserId);
+
+        setDefaultContentCaptureServiceEnabled(false);
+        try {
+            executeDeviceTestMethod(".ContentCaptureRestrictionsTest",
+                    "testDisallowContentCapture_allowed");
+        } finally {
+            setDefaultContentCaptureServiceEnabled(true);
+        }
+    }
+
+    private void setDefaultContentCaptureServiceEnabled(boolean enabled)
+            throws Exception {
+        CLog.d("setDefaultServiceEnabled(" + mUserId + "): " + enabled);
+        getDevice().executeShellCommand(
+                "cmd content_capture set default-service-enabled " + mUserId + " " + enabled);
+    }
+
     public void testSetMeteredDataDisabledPackages() throws Exception {
         if (!mHasFeature) {
             return;
@@ -1846,4 +1879,19 @@
         getDevice().executeShellCommand(
                 restricted ? RESTRICT_BACKGROUND_ON_CMD : RESTRICT_BACKGROUND_OFF_CMD);
     }
+
+    // TODO: copied from RequiredServiceRule, which is on compatibility-device-util
+    // (and we use compatibility-host-util)
+    public boolean hasService(String service) {
+        // TODO: ideally should call SystemServiceManager directly, but we would need to open
+        // some @Testing APIs for that.
+        String command = "service check " + service;
+        try {
+            String commandOutput = getDevice().executeShellCommand(command);
+            return !commandOutput.contains("not found");
+        } catch (Exception e) {
+            CLog.w("Exception running '" + command + "': " + e);
+            return false;
+        }
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
index 803ae3f..fd9a0d6 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
@@ -49,18 +49,42 @@
         super.tearDown();
     }
 
-    public void testQuietMode() throws Exception {
+    public void testQuietMode_defaultForegroundLauncher() throws Exception {
         if (!mHasFeature) {
           return;
         }
         runDeviceTestsAsUser(
                 TEST_PACKAGE,
                 TEST_CLASS,
-                null,
+                "testTryEnableQuietMode_defaultForegroundLauncher",
                 mPrimaryUserId,
                 createParams(mProfileId));
     }
 
+    public void testQuietMode_notForegroundLauncher() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(
+            TEST_PACKAGE,
+            TEST_CLASS,
+            "testTryEnableQuietMode_notForegroundLauncher",
+            mPrimaryUserId,
+            createParams(mProfileId));
+    }
+
+    public void testQuietMode_notDefaultLauncher() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(
+            TEST_PACKAGE,
+            TEST_CLASS,
+            "testTryEnableQuietMode_notDefaultLauncher",
+            mPrimaryUserId,
+            createParams(mProfileId));
+    }
+
     private void createAndStartManagedProfile() throws Exception {
         mProfileId = createManagedProfile(mPrimaryUserId);
         switchUser(mPrimaryUserId);
diff --git a/hostsidetests/dexmetadata/host/Android.mk b/hostsidetests/dexmetadata/host/Android.mk
index a51ddd2..cae13cd 100644
--- a/hostsidetests/dexmetadata/host/Android.mk
+++ b/hostsidetests/dexmetadata/host/Android.mk
@@ -29,6 +29,6 @@
     tradefed
 
 # tag this module as test artifact for cts
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/edi/AndroidTest.xml b/hostsidetests/edi/AndroidTest.xml
index b0d5d9f..aea1030 100644
--- a/hostsidetests/edi/AndroidTest.xml
+++ b/hostsidetests/edi/AndroidTest.xml
@@ -16,8 +16,9 @@
 <configuration description="Config for CTS EDI host test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="deviceinfo" />
-    <!-- Included not for instant-app but to collect the required information for the run -->
-    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <!-- Do no need to run instant mode for collecting information -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsEdiHostTestCases.jar" />
     </test>
diff --git a/hostsidetests/gputools/Android.mk b/hostsidetests/gputools/Android.mk
index b2946be..7f1d242 100644
--- a/hostsidetests/gputools/Android.mk
+++ b/hostsidetests/gputools/Android.mk
@@ -20,7 +20,7 @@
 LOCAL_MODULE_TAGS := tests
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts cts_instant
 
 LOCAL_MODULE := CtsGpuToolsHostTestCases
 
diff --git a/hostsidetests/gputools/AndroidTest.xml b/hostsidetests/gputools/AndroidTest.xml
index 199f5e7..53419cd 100644
--- a/hostsidetests/gputools/AndroidTest.xml
+++ b/hostsidetests/gputools/AndroidTest.xml
@@ -17,6 +17,8 @@
 <configuration description="Config for CtsGpuToolsHostTestCases">
     <option name="test-suite-tag" value="cts" />
     <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" />
     <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/apps/Android.mk b/hostsidetests/gputools/apps/Android.mk
index 138b4e9..0f2760a 100644
--- a/hostsidetests/gputools/apps/Android.mk
+++ b/hostsidetests/gputools/apps/Android.mk
@@ -34,7 +34,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts cts_instant
 
 LOCAL_MULTILIB := both
 
@@ -45,7 +45,8 @@
 --rename-manifest-package android.rootlessgpudebug.DEBUG.app \
 --debug-mode
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 
@@ -68,6 +69,8 @@
 LOCAL_AAPT_FLAGS := \
 --rename-manifest-package android.rootlessgpudebug.RELEASE.app
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/gputools/apps/AndroidManifest.xml b/hostsidetests/gputools/apps/AndroidManifest.xml
index fab44c3..0e033f3 100755
--- a/hostsidetests/gputools/apps/AndroidManifest.xml
+++ b/hostsidetests/gputools/apps/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.rootlessgpudebug.app">>
+    package="android.rootlessgpudebug.app"
+    android:targetSandboxVersion="2">
 
     <application android:extractNativeLibs="true" >
         <activity android:name=".RootlessGpuDebugDeviceActivity" >
diff --git a/hostsidetests/gputools/layers/Android.mk b/hostsidetests/gputools/layers/Android.mk
index f91b0d3..29e832f 100644
--- a/hostsidetests/gputools/layers/Android.mk
+++ b/hostsidetests/gputools/layers/Android.mk
@@ -89,7 +89,7 @@
 LOCAL_SDK_VERSION := current
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts cts_instant
 
 LOCAL_MULTILIB := both
 
@@ -101,6 +101,8 @@
 libGLES_glesLayer2 \
 libGLES_glesLayer3
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/gputools/layers/AndroidManifest.xml b/hostsidetests/gputools/layers/AndroidManifest.xml
index 2b187ad..6b58238 100755
--- a/hostsidetests/gputools/layers/AndroidManifest.xml
+++ b/hostsidetests/gputools/layers/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.rootlessgpudebug.LAYERS.app">
+    package="android.rootlessgpudebug.LAYERS.app"
+    android:targetSandboxVersion="2">
 
     <application android:extractNativeLibs="true" android:debuggable="false"
         android:hasCode="false">
diff --git a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
index a3e51e1..2a0ee1e 100644
--- a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
+++ b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
@@ -207,6 +207,10 @@
             apkIn.close();
         }
 
+        // If this assert fires , try increasing the timeout
+        Assert.assertTrue("Log scanning did not complete before timout (" +
+                LOG_SEARCH_TIMEOUT_MS + "ms)", scanComplete);
+
         return result;
     }
 
diff --git a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk b/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
index 365f792..73d4b84 100644
--- a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
+++ b/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
@@ -36,6 +36,6 @@
 LOCAL_PACKAGE_NAME := CtsInputMethodServiceEventProvider
 
 LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 19
+LOCAL_MIN_SDK_VERSION := 26
 
 include $(BUILD_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml b/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml
index 9189da3..841b7c1 100755
--- a/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml
+++ b/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.inputmethodservice.cts.provider">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="25" />
+    <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26" />
 
     <application android:label="CtsInputMethodServiceEventProvider">
         <provider
diff --git a/hostsidetests/sample/AndroidTest.xml b/hostsidetests/sample/AndroidTest.xml
index 5539166..0b49219 100644
--- a/hostsidetests/sample/AndroidTest.xml
+++ b/hostsidetests/sample/AndroidTest.xml
@@ -16,7 +16,8 @@
 <configuration description="Config for CTS Sample host test cases">
     <option name="test-suite-tag" value="cts" />
     <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="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="CtsSampleDeviceApp.apk" />
diff --git a/hostsidetests/shortcuts/hostside/AndroidTest.xml b/hostsidetests/shortcuts/hostside/AndroidTest.xml
index 2f1c7f0..bc6ca74 100644
--- a/hostsidetests/shortcuts/hostside/AndroidTest.xml
+++ b/hostsidetests/shortcuts/hostside/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <!-- 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" />
     <target_preparer class="android.cts.backup.BackupPreparer">
         <option name="enable-backup-if-needed" value="true" />
         <option name="select-local-transport" value="true" />
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 410d01f..abb293b 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -544,6 +544,7 @@
         if (statsdDisabled()) {
             return;
         }
+        if (!hasFeature(FEATURE_WATCH, false)) return;
         final int atomTag = Atom.OVERLAY_STATE_CHANGED_FIELD_NUMBER;
 
         Set<Integer> entered = new HashSet<>(
@@ -1112,7 +1113,7 @@
         }
 
         // Make device side test package a role holder
-        String callScreenAppRole = "android.app.role.CALL_SCREENING_APP";
+        String callScreenAppRole = "android.app.role.CALL_SCREENING";
         getDevice().executeShellCommand(
                 "cmd role add-role-holder " + callScreenAppRole + " " + DEVICE_SIDE_TEST_PACKAGE);
 
diff --git a/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java b/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java
index e8515d9..9840b19 100644
--- a/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java
+++ b/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java
@@ -53,13 +53,15 @@
 
     @Override
     public void onTileAdded() {
+        super.onTileAdded();
         Log.i(TAG, TEST_PREFIX + "onTileAdded");
+        super.onTileAdded();
     }
 
     @Override
     public void onTileRemoved() {
-        Log.i(TAG, TEST_PREFIX + "onTileRemoved");
         super.onTileRemoved();
+        Log.i(TAG, TEST_PREFIX + "onTileRemoved");
     }
 
     @Override
@@ -71,11 +73,11 @@
         registerReceiver(mReceiver, filter);
 
         // Set up some initial good state.
-        getQsTile().setLabel(TAG);
-        getQsTile().setContentDescription("CTS Test Tile");
-        getQsTile().setIcon(Icon.createWithResource(this, android.R.drawable.ic_secure));
-        getQsTile().setState(Tile.STATE_ACTIVE);
-        getQsTile().updateTile();
+        super.getQsTile().setLabel(TAG);
+        super.getQsTile().setContentDescription("CTS Test Tile");
+        super.getQsTile().setIcon(Icon.createWithResource(this, android.R.drawable.ic_secure));
+        super.getQsTile().setState(Tile.STATE_ACTIVE);
+        super.getQsTile().updateTile();
     }
 
     @Override
@@ -89,9 +91,9 @@
     public void onClick() {
         super.onClick();
         Log.i(TAG, TEST_PREFIX + "onClick");
-        Log.i(TAG, TEST_PREFIX + "is_secure_" + isSecure());
-        Log.i(TAG, TEST_PREFIX + "is_locked_" + isLocked());
-        unlockAndRun(new Runnable() {
+        Log.i(TAG, TEST_PREFIX + "is_secure_" + super.isSecure());
+        Log.i(TAG, TEST_PREFIX + "is_locked_" + super.isLocked());
+        super.unlockAndRun(new Runnable() {
             @Override
             public void run() {
                 Log.i(TAG, TEST_PREFIX + "unlockAndRunRun");
@@ -100,7 +102,7 @@
     }
 
     private void handleStartActivity() {
-        startActivityAndCollapse(new Intent(Settings.ACTION_SETTINGS)
+        super.startActivityAndCollapse(new Intent(Settings.ACTION_SETTINGS)
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
     }
 
@@ -109,7 +111,7 @@
         final Dialog dialog = new Dialog(this);
         dialog.setContentView(new FocusView(this, dialog));
         try {
-            showDialog(dialog);
+            super.showDialog(dialog);
         } catch (Exception e) {
             Log.i(TAG, TEST_PREFIX + "onWindowAddFailed", e);
         }
diff --git a/hostsidetests/theme/app/src/android/theme/app/ConditionCheck.java b/hostsidetests/theme/app/src/android/theme/app/ConditionCheck.java
new file mode 100644
index 0000000..8954a8d
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/ConditionCheck.java
@@ -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.theme.app;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Runnable that re-posts itself on a handler until either all of the conditions are satisfied
+ * or a retry threshold is exceeded.
+ */
+class ConditionCheck implements Runnable {
+    private static final int MAX_RETRIES = 3;
+    private static final int RETRY_DELAY = 500;
+
+    private final Handler mHandler;
+    private final Runnable mOnSuccess;
+    private final Consumer<String> mOnFailure;
+    private final ArrayList<Pair<String, Supplier<Boolean>>> mConditions = new ArrayList<>();
+
+    private ArrayList<Pair<String, Supplier<Boolean>>> mRemainingConditions = new ArrayList<>();
+    private int mRemainingRetries;
+
+    ConditionCheck(Context context, Runnable onSuccess, Consumer<String> onFailure) {
+        mHandler = new Handler(context.getMainLooper());
+        mOnSuccess = onSuccess;
+        mOnFailure = onFailure;
+    }
+
+    public ConditionCheck addCondition(String summary, Supplier<Boolean> condition) {
+        mConditions.add(new Pair<>(summary, condition));
+        return this;
+    }
+
+    public void start() {
+        mRemainingConditions = new ArrayList<>(mConditions);
+        mRemainingRetries = 0;
+
+        mHandler.removeCallbacks(this);
+        mHandler.post(this);
+    }
+
+    public void cancel() {
+        mHandler.removeCallbacks(this);
+    }
+
+    @Override
+    public void run() {
+        mRemainingConditions.removeIf(condition -> condition.second.get());
+        if (mRemainingConditions.isEmpty()) {
+            mOnSuccess.run();
+        } else if (mRemainingRetries < MAX_RETRIES) {
+            mRemainingRetries++;
+            mHandler.removeCallbacks(this);
+            mHandler.postDelayed(this, RETRY_DELAY);
+        } else {
+            final StringBuffer buffer = new StringBuffer("Failed conditions:");
+            mRemainingConditions.forEach(condition ->
+                    buffer.append("\n").append(condition.first));
+            mOnFailure.accept(buffer.toString());
+        }
+    }
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
index 3591410..a41e426 100644
--- a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
@@ -16,27 +16,20 @@
 
 package android.theme.app;
 
-import android.Manifest.permission;
+import static android.theme.app.TestConfiguration.THEMES;
+
 import android.app.Activity;
-import android.app.KeyguardManager;
-import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.os.Build.VERSION;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.Handler;
 import android.util.Log;
-import android.util.Pair;
 import android.view.WindowManager.LayoutParams;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
 
 /**
  * Generates images by iterating through all themes and launching instances of
@@ -69,16 +62,9 @@
         mOutputDir = setupOutputDirectory();
         if (mOutputDir == null) {
             finish("Failed to create output directory " + mOutputDir.getAbsolutePath(), false);
+        } else {
+            generateNextImage();
         }
-
-        // The activity has been created, but we don't want to start image generation until various
-        // asynchronous conditions are satisfied.
-        new ConditionCheck(this, () -> generateNextImage(), message -> finish(message, false))
-                .addCondition("Device is unlocked",
-                        () -> !getSystemService(KeyguardManager.class).isDeviceLocked())
-                .addCondition("Window is focused",
-                        () -> hasWindowFocus())
-                .start();
     }
 
     private File setupOutputDirectory() {
@@ -93,63 +79,6 @@
     }
 
     /**
-     * Runnable that re-posts itself on a handler until either all of the conditions are satisfied
-     * or a retry threshold is exceeded.
-     */
-    class ConditionCheck implements Runnable {
-        private static final int MAX_RETRIES = 3;
-        private static final int RETRY_DELAY = 500;
-
-        private final Handler mHandler;
-        private final Runnable mOnSuccess;
-        private final Consumer<String> mOnFailure;
-        private final ArrayList<Pair<String, Supplier<Boolean>>> mConditions = new ArrayList<>();
-
-        private ArrayList<Pair<String, Supplier<Boolean>>> mRemainingConditions = new ArrayList<>();
-        private int mRemainingRetries;
-
-        ConditionCheck(Context context, Runnable onSuccess, Consumer<String> onFailure) {
-            mHandler = new Handler(context.getMainLooper());
-            mOnSuccess = onSuccess;
-            mOnFailure = onFailure;
-        }
-
-        public ConditionCheck addCondition(String summary, Supplier<Boolean> condition) {
-            mConditions.add(new Pair<>(summary, condition));
-            return this;
-        }
-
-        public void start() {
-            mRemainingConditions = new ArrayList<>(mConditions);
-            mRemainingRetries = 0;
-
-            mHandler.removeCallbacks(this);
-            mHandler.post(this);
-        }
-
-        public void cancel() {
-            mHandler.removeCallbacks(this);
-        }
-
-        @Override
-        public void run() {
-            mRemainingConditions.removeIf(condition -> condition.second.get());
-            if (mRemainingConditions.isEmpty()) {
-                mOnSuccess.run();
-            } else if (mRemainingRetries < MAX_RETRIES) {
-                mRemainingRetries++;
-                mHandler.removeCallbacks(this);
-                mHandler.postDelayed(this, RETRY_DELAY);
-            } else {
-                final StringBuffer buffer = new StringBuffer("Failed conditions:");
-                mRemainingConditions.forEach(condition ->
-                        buffer.append("\n").append(condition.first));
-                mOnFailure.accept(buffer.toString());
-            }
-        }
-    }
-
-    /**
      * @return whether the test finished successfully
      */
     public boolean isFinishSuccess() {
@@ -167,8 +96,23 @@
     /**
      * Starts the activity to generate the next image.
      */
-    private boolean generateNextImage() {
-        final ThemeDeviceActivity.Theme theme = ThemeDeviceActivity.THEMES[mCurrentTheme];
+    private void generateNextImage() {
+        // Keep trying themes until one works.
+        boolean success = false;
+        while (++mCurrentTheme < THEMES.length && !success) {
+            success = launchThemeDeviceActivity();
+        }
+
+        // If we ran out of themes, we're done.
+        if (!success) {
+            compressOutput();
+
+            finish("Image generation complete!", true);
+        }
+    }
+
+    private boolean launchThemeDeviceActivity() {
+        final ThemeInfo theme = THEMES[mCurrentTheme];
         if (theme.apiLevel > VERSION.SDK_INT) {
             Log.v(TAG, "Skipping theme \"" + theme.name
                     + "\" (requires API " + theme.apiLevel + ")");
@@ -193,18 +137,7 @@
             return;
         }
 
-        // Keep trying themes until one works.
-        boolean success = false;
-        while (++mCurrentTheme < ThemeDeviceActivity.THEMES.length && !success) {
-            success = generateNextImage();
-        }
-
-        // If we ran out of themes, we're done.
-        if (!success) {
-            compressOutput();
-
-            finish("Image generation complete!", true);
-        }
+        generateNextImage();
     }
 
     private void compressOutput() {
diff --git a/hostsidetests/theme/app/src/android/theme/app/LayoutInfo.java b/hostsidetests/theme/app/src/android/theme/app/LayoutInfo.java
new file mode 100644
index 0000000..e7beab7e
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/LayoutInfo.java
@@ -0,0 +1,38 @@
+/*
+ * 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.theme.app;
+
+import android.theme.app.modifiers.AbstractLayoutModifier;
+
+/**
+ * A class to encapsulate information about a layout.
+ */
+class LayoutInfo {
+    public final int id;
+    public final String name;
+    public final AbstractLayoutModifier modifier;
+
+    LayoutInfo(int id, String name) {
+        this(id, name, null);
+    }
+
+    LayoutInfo(int id, String name, AbstractLayoutModifier modifier) {
+        this.id = id;
+        this.name = name;
+        this.modifier = modifier;
+    }
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/LayoutModifier.java b/hostsidetests/theme/app/src/android/theme/app/LayoutModifier.java
deleted file mode 100644
index e007129..0000000
--- a/hostsidetests/theme/app/src/android/theme/app/LayoutModifier.java
+++ /dev/null
@@ -1,41 +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.
- */
-
-package android.theme.app;
-
-import android.view.View;
-
-/**
- * Interface used to do further setup on a view after it has been inflated.
- */
-public interface LayoutModifier {
-
-    /**
-     * Modifies the view before it has been added to a parent. Useful for avoiding animations in
-     * response to setter calls.
-     *
-     * @param view the view inflated by the test activity
-     */
-    void modifyViewBeforeAdd(View view);
-
-    /**
-     * Modifies the view after it has been added to a parent. Useful for running animations in
-     * response to setter calls.
-     *
-     * @param view the view inflated by the test activity
-     */
-    void modifyViewAfterAdd(View view);
-}
diff --git a/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
new file mode 100644
index 0000000..d6c9f1c
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
@@ -0,0 +1,229 @@
+/*
+ * 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.theme.app;
+
+import android.os.Build;
+import android.theme.app.modifiers.DatePickerModifier;
+import android.theme.app.modifiers.ProgressBarModifier;
+import android.theme.app.modifiers.SearchViewModifier;
+import android.theme.app.modifiers.ViewCheckedModifier;
+import android.theme.app.modifiers.ViewPressedModifier;
+import android.theme.app.modifiers.TimePickerModifier;
+
+/**
+ * Constants defining the themes and layouts to be verified.
+ */
+public class TestConfiguration {
+    @SuppressWarnings("deprecation")
+    static final ThemeInfo[] THEMES = {
+            // Holo
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo,
+                    Build.VERSION_CODES.HONEYCOMB, "holo"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog_MinWidth,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog_minwidth"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar_MinWidth,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar_minwidth"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_DialogWhenLarge,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_DialogWhenLarge_NoActionBar,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge_noactionbar"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_InputMethod,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_inputmethod"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar_Fullscreen,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar_fullscreen"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar_Overscan,
+                    Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_noactionbar_overscan"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar_TranslucentDecor,
+                    Build.VERSION_CODES.KITKAT, "holo_noactionbar_translucentdecor"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Panel,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_panel"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Wallpaper,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Wallpaper_NoTitleBar,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper_notitlebar"),
+
+            // Holo Light
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_DarkActionBar,
+                    Build.VERSION_CODES.ICE_CREAM_SANDWICH, "holo_light_darkactionbar"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog_MinWidth,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_minwidth"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar_MinWidth,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar_minwidth"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge_NoActionBar,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge_noactionbar"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar,
+                    Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen,
+                    Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar_fullscreen"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Overscan,
+                    Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_light_noactionbar_overscan"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_TranslucentDecor,
+                    Build.VERSION_CODES.KITKAT, "holo_light_noactionbar_translucentdecor"),
+            new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Panel,
+                    Build.VERSION_CODES.HONEYCOMB, "holo_light_panel"),
+
+            // Material
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material,
+                    Build.VERSION_CODES.LOLLIPOP, "material"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialog"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_Alert,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_alert"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_MinWidth,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_minwidth"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar_MinWidth,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar_minwidth"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_Presentation,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_presentation"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge_NoActionBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge_noactionbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_InputMethod,
+                    Build.VERSION_CODES.LOLLIPOP, "material_inputmethod"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar_Fullscreen,
+                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_fullscreen"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar_Overscan,
+                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_overscan"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar_TranslucentDecor,
+                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_translucentdecor"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Panel,
+                    Build.VERSION_CODES.LOLLIPOP, "material_panel"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Settings,
+                    Build.VERSION_CODES.LOLLIPOP, "material_settings"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Voice,
+                    Build.VERSION_CODES.LOLLIPOP, "material_voice"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Wallpaper,
+                    Build.VERSION_CODES.LOLLIPOP, "material_wallpaper"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Wallpaper_NoTitleBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_wallpaper_notitlebar"),
+
+            // Material Light
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_DarkActionBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_darkactionbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Alert,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_alert"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_MinWidth,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_minwidth"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar_MinWidth,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar_minwidth"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Presentation,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_presentation"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge_NoActionBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge_noactionbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_LightStatusBar,
+                    Build.VERSION_CODES.M, "material_light_lightstatusbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Fullscreen,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_fullscreen"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Overscan,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_overscan"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_TranslucentDecor,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_translucentdecor"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Panel,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_panel"),
+            new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Voice,
+                    Build.VERSION_CODES.LOLLIPOP, "material_light_voice")
+    };
+
+    static final LayoutInfo[] LAYOUTS = {
+            new LayoutInfo(R.layout.button, "button"),
+            new LayoutInfo(R.layout.button, "button_pressed",
+                    new ViewPressedModifier()),
+            new LayoutInfo(R.layout.checkbox, "checkbox"),
+            new LayoutInfo(R.layout.checkbox, "checkbox_checked",
+                    new ViewCheckedModifier()),
+            new LayoutInfo(R.layout.chronometer, "chronometer"),
+            new LayoutInfo(R.layout.color_blue_bright, "color_blue_bright"),
+            new LayoutInfo(R.layout.color_blue_dark, "color_blue_dark"),
+            new LayoutInfo(R.layout.color_blue_light, "color_blue_light"),
+            new LayoutInfo(R.layout.color_green_dark, "color_green_dark"),
+            new LayoutInfo(R.layout.color_green_light, "color_green_light"),
+            new LayoutInfo(R.layout.color_orange_dark, "color_orange_dark"),
+            new LayoutInfo(R.layout.color_orange_light, "color_orange_light"),
+            new LayoutInfo(R.layout.color_purple, "color_purple"),
+            new LayoutInfo(R.layout.color_red_dark, "color_red_dark"),
+            new LayoutInfo(R.layout.color_red_light, "color_red_light"),
+            new LayoutInfo(R.layout.datepicker, "datepicker",
+                    new DatePickerModifier()),
+            new LayoutInfo(R.layout.edittext, "edittext"),
+            new LayoutInfo(R.layout.progressbar_horizontal_0, "progressbar_horizontal_0"),
+            new LayoutInfo(R.layout.progressbar_horizontal_100, "progressbar_horizontal_100"),
+            new LayoutInfo(R.layout.progressbar_horizontal_50, "progressbar_horizontal_50"),
+            new LayoutInfo(R.layout.progressbar_large, "progressbar_large",
+                    new ProgressBarModifier()),
+            new LayoutInfo(R.layout.progressbar_small, "progressbar_small",
+                    new ProgressBarModifier()),
+            new LayoutInfo(R.layout.progressbar, "progressbar",
+                    new ProgressBarModifier()),
+            new LayoutInfo(R.layout.radiobutton_checked, "radiobutton_checked"),
+            new LayoutInfo(R.layout.radiobutton, "radiobutton"),
+            new LayoutInfo(R.layout.radiogroup_horizontal, "radiogroup_horizontal"),
+            new LayoutInfo(R.layout.radiogroup_vertical, "radiogroup_vertical"),
+            new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0"),
+            new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5"),
+            new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5"),
+            new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0_pressed",
+                    new ViewPressedModifier()),
+            new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5_pressed",
+                    new ViewPressedModifier()),
+            new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5_pressed",
+                    new ViewPressedModifier()),
+            new LayoutInfo(R.layout.searchview, "searchview_query",
+                    new SearchViewModifier(SearchViewModifier.QUERY)),
+            new LayoutInfo(R.layout.searchview, "searchview_query_hint",
+                    new SearchViewModifier(SearchViewModifier.QUERY_HINT)),
+            new LayoutInfo(R.layout.seekbar_0, "seekbar_0"),
+            new LayoutInfo(R.layout.seekbar_100, "seekbar_100"),
+            new LayoutInfo(R.layout.seekbar_50, "seekbar_50"),
+            new LayoutInfo(R.layout.spinner, "spinner"),
+            new LayoutInfo(R.layout.switch_button_checked, "switch_button_checked"),
+            new LayoutInfo(R.layout.switch_button, "switch_button"),
+            new LayoutInfo(R.layout.textview, "textview"),
+            new LayoutInfo(R.layout.timepicker, "timepicker",
+                    new TimePickerModifier()),
+            new LayoutInfo(R.layout.togglebutton_checked, "togglebutton_checked"),
+            new LayoutInfo(R.layout.togglebutton, "togglebutton"),
+    };
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java b/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java
index b30ffd3..9227edd 100644
--- a/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java
@@ -16,19 +16,17 @@
 
 package android.theme.app;
 
+import static android.theme.app.TestConfiguration.LAYOUTS;
+import static android.theme.app.TestConfiguration.THEMES;
+
 import android.animation.ValueAnimator;
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
-import android.os.Build;
 import android.os.Bundle;
-import android.theme.app.modifiers.DatePickerModifier;
-import android.theme.app.modifiers.ProgressBarModifier;
-import android.theme.app.modifiers.SearchViewModifier;
-import android.theme.app.modifiers.TimePickerModifier;
-import android.theme.app.modifiers.ViewCheckedModifier;
-import android.theme.app.modifiers.ViewPressedModifier;
+import android.theme.app.modifiers.AbstractLayoutModifier;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -36,7 +34,6 @@
 import android.widget.DatePicker;
 
 import java.io.File;
-import java.lang.Override;
 
 /**
  * A activity which display various UI elements with non-modifiable themes.
@@ -53,7 +50,7 @@
      */
     private static final long HOLO_CALENDAR_VIEW_ADJUSTMENT_DURATION = 540;
 
-    private Theme mTheme;
+    private ThemeInfo mTheme;
     private ReferenceViewGroup mViewGroup;
     private File mOutputDir;
     private int mLayoutIndex;
@@ -94,9 +91,18 @@
 
         mViewGroup = findViewById(R.id.reference_view_group);
 
-        getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON
-                | LayoutParams.FLAG_TURN_SCREEN_ON
-                | LayoutParams.FLAG_DISMISS_KEYGUARD );
+        getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+        // The activity has been created, but we don't want to start image generation until various
+        // asynchronous conditions are satisfied.
+        new ConditionCheck(this, () -> setNextLayout(), message -> finish(message, false))
+                .addCondition("Device is unlocked",
+                        () -> !getSystemService(KeyguardManager.class).isDeviceLocked())
+                .addCondition("Window is focused",
+                        () -> hasWindowFocus())
+                .addCondition("Activity is resumed",
+                        () -> mIsRunning)
+                .start();
     }
 
     @Override
@@ -104,8 +110,6 @@
         super.onResume();
 
         mIsRunning = true;
-
-        setNextLayout();
     }
 
     @Override
@@ -115,8 +119,7 @@
         if (!isFinishing()) {
             // The activity paused for some reason, likely a system crash
             // dialog. Finish it so we can move to the next theme.
-            Log.w(TAG, "onPause() called without a call to finish()", new RuntimeException());
-            finish();
+            Log.e(TAG, "onPause() called without a call to finish(), check system dialogs");
         }
 
         super.onPause();
@@ -125,10 +128,7 @@
     @Override
     protected void onDestroy() {
         if (mLayoutIndex < LAYOUTS.length) {
-            final Intent data = new Intent();
-            data.putExtra(GenerateImagesActivity.EXTRA_REASON, "Only rendered "
-                    + mLayoutIndex + "/" + LAYOUTS.length + " layouts");
-            setResult(RESULT_CANCELED, data);
+            finish("Only rendered " + mLayoutIndex + "/" + LAYOUTS.length + " layouts", false);
         }
 
         super.onDestroy();
@@ -139,15 +139,14 @@
      */
     private void setNextLayout() {
         if (mLayoutIndex >= LAYOUTS.length) {
-            setResult(RESULT_OK);
-            finish();
+            finish("Rendered all layouts", true);
             return;
         }
 
         mViewGroup.removeAllViews();
 
-        final Layout layout = LAYOUTS[mLayoutIndex++];
-        final LayoutModifier modifier = layout.modifier;
+        final LayoutInfo layout = LAYOUTS[mLayoutIndex++];
+        final AbstractLayoutModifier modifier = layout.modifier;
         final String layoutName = String.format("%s_%s", mTheme.name, layout.name);
         final LayoutInflater layoutInflater = LayoutInflater.from(mViewGroup.getContext());
         final View view = layoutInflater.inflate(layout.id, mViewGroup, false);
@@ -166,9 +165,9 @@
                 + " (" + mLayoutIndex + "/" + LAYOUTS.length + ")");
 
         final Runnable generateBitmapRunnable = () ->
-            new BitmapTask(view, layoutName, modifier).execute();
+            new BitmapTask(view, layoutName).execute();
 
-        if (view instanceof DatePicker && mTheme.spec == Theme.HOLO) {
+        if (view instanceof DatePicker && mTheme.spec == ThemeInfo.HOLO) {
             // The Holo-styled DatePicker uses a CalendarView that has a
             // non-configurable adjustment duration of 540ms.
             view.postDelayed(generateBitmapRunnable, HOLO_CALENDAR_VIEW_ADJUSTMENT_DURATION);
@@ -177,13 +176,20 @@
         }
     }
 
+    private void finish(String reason, boolean success) {
+        final Intent data = new Intent();
+        data.putExtra(GenerateImagesActivity.EXTRA_REASON, reason);
+        setResult(success ? RESULT_OK : RESULT_CANCELED, data);
+
+        if (!isFinishing()) {
+            finish();
+        }
+    }
+
     private class BitmapTask extends GenerateBitmapTask {
-        private final LayoutModifier mLayoutModifier;
 
-        public BitmapTask(View view, String name, LayoutModifier modifier) {
+        public BitmapTask(View view, String name) {
             super(view, mOutputDir, name);
-
-            mLayoutModifier = modifier;
         }
 
         @Override
@@ -191,250 +197,9 @@
             if (success && mIsRunning) {
                 setNextLayout();
             } else {
-                Log.e(TAG, "Failed to render view to bitmap: " + mName + " (activity running? "
-                        + mIsRunning + ")");
-                finish();
+                finish("Failed to render view to bitmap: " + mName + " (activity running? "
+                        + mIsRunning + ")", false);
             }
         }
     }
-
-    /**
-     * A class to encapsulate information about a theme.
-     */
-    static class Theme {
-        public static final int HOLO = 0;
-        public static final int MATERIAL = 1;
-
-        public final int spec;
-        public final int id;
-        public final int apiLevel;
-        public final String name;
-
-        private Theme(int spec, int id, int apiLevel, String name) {
-            this.spec = spec;
-            this.id = id;
-            this.apiLevel = apiLevel;
-            this.name = name;
-        }
-    }
-
-    // List of themes to verify.
-    @SuppressWarnings("deprecation")
-    static final Theme[] THEMES = {
-            // Holo
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo,
-                    Build.VERSION_CODES.HONEYCOMB, "holo"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog_MinWidth,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog_minwidth"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar_MinWidth,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar_minwidth"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_DialogWhenLarge,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_DialogWhenLarge_NoActionBar,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge_noactionbar"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_InputMethod,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_inputmethod"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar_Fullscreen,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar_fullscreen"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar_Overscan,
-                    Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_noactionbar_overscan"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar_TranslucentDecor,
-                    Build.VERSION_CODES.KITKAT, "holo_noactionbar_translucentdecor"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Panel,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_panel"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Wallpaper,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Wallpaper_NoTitleBar,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper_notitlebar"),
-
-            // Holo Light
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_DarkActionBar,
-                    Build.VERSION_CODES.ICE_CREAM_SANDWICH, "holo_light_darkactionbar"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog_MinWidth,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_minwidth"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar_MinWidth,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar_minwidth"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge_NoActionBar,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge_noactionbar"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar,
-                    Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen,
-                    Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar_fullscreen"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Overscan,
-                    Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_light_noactionbar_overscan"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_TranslucentDecor,
-                    Build.VERSION_CODES.KITKAT, "holo_light_noactionbar_translucentdecor"),
-            new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Panel,
-                    Build.VERSION_CODES.HONEYCOMB, "holo_light_panel"),
-
-            // Material
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material,
-                    Build.VERSION_CODES.LOLLIPOP, "material"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialog"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_Alert,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_alert"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_MinWidth,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_minwidth"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar_MinWidth,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar_minwidth"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_Presentation,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialog_presentation"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge_NoActionBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge_noactionbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_InputMethod,
-                    Build.VERSION_CODES.LOLLIPOP, "material_inputmethod"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar_Fullscreen,
-                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_fullscreen"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar_Overscan,
-                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_overscan"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar_TranslucentDecor,
-                    Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_translucentdecor"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Panel,
-                    Build.VERSION_CODES.LOLLIPOP, "material_panel"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Settings,
-                    Build.VERSION_CODES.LOLLIPOP, "material_settings"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Voice,
-                    Build.VERSION_CODES.LOLLIPOP, "material_voice"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Wallpaper,
-                    Build.VERSION_CODES.LOLLIPOP, "material_wallpaper"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Wallpaper_NoTitleBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_wallpaper_notitlebar"),
-
-            // Material Light
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_DarkActionBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_darkactionbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Alert,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_alert"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_MinWidth,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_minwidth"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar_MinWidth,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar_minwidth"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Presentation,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_presentation"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge_NoActionBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge_noactionbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_LightStatusBar,
-                    Build.VERSION_CODES.M, "material_light_lightstatusbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Fullscreen,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_fullscreen"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Overscan,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_overscan"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_TranslucentDecor,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_translucentdecor"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Panel,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_panel"),
-            new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Voice,
-                    Build.VERSION_CODES.LOLLIPOP, "material_light_voice")
-    };
-
-    /**
-     * A class to encapsulate information about a layout.
-     */
-    private static class Layout {
-        public final int id;
-        public final String name;
-        public final LayoutModifier modifier;
-
-        private Layout(int id, String name) {
-            this(id, name, null);
-        }
-
-        private Layout(int id, String name, LayoutModifier modifier) {
-            this.id = id;
-            this.name = name;
-            this.modifier = modifier;
-        }
-    }
-
-    // List of layouts to verify for each theme.
-    private static final Layout[] LAYOUTS = {
-            new Layout(R.layout.button, "button"),
-            new Layout(R.layout.button, "button_pressed",
-                    new ViewPressedModifier()),
-            new Layout(R.layout.checkbox, "checkbox"),
-            new Layout(R.layout.checkbox, "checkbox_checked",
-                    new ViewCheckedModifier()),
-            new Layout(R.layout.chronometer, "chronometer"),
-            new Layout(R.layout.color_blue_bright, "color_blue_bright"),
-            new Layout(R.layout.color_blue_dark, "color_blue_dark"),
-            new Layout(R.layout.color_blue_light, "color_blue_light"),
-            new Layout(R.layout.color_green_dark, "color_green_dark"),
-            new Layout(R.layout.color_green_light, "color_green_light"),
-            new Layout(R.layout.color_orange_dark, "color_orange_dark"),
-            new Layout(R.layout.color_orange_light, "color_orange_light"),
-            new Layout(R.layout.color_purple, "color_purple"),
-            new Layout(R.layout.color_red_dark, "color_red_dark"),
-            new Layout(R.layout.color_red_light, "color_red_light"),
-            new Layout(R.layout.datepicker, "datepicker",
-                    new DatePickerModifier()),
-            new Layout(R.layout.edittext, "edittext"),
-            new Layout(R.layout.progressbar_horizontal_0, "progressbar_horizontal_0"),
-            new Layout(R.layout.progressbar_horizontal_100, "progressbar_horizontal_100"),
-            new Layout(R.layout.progressbar_horizontal_50, "progressbar_horizontal_50"),
-            new Layout(R.layout.progressbar_large, "progressbar_large",
-                    new ProgressBarModifier()),
-            new Layout(R.layout.progressbar_small, "progressbar_small",
-                    new ProgressBarModifier()),
-            new Layout(R.layout.progressbar, "progressbar",
-                    new ProgressBarModifier()),
-            new Layout(R.layout.radiobutton_checked, "radiobutton_checked"),
-            new Layout(R.layout.radiobutton, "radiobutton"),
-            new Layout(R.layout.radiogroup_horizontal, "radiogroup_horizontal"),
-            new Layout(R.layout.radiogroup_vertical, "radiogroup_vertical"),
-            new Layout(R.layout.ratingbar_0, "ratingbar_0"),
-            new Layout(R.layout.ratingbar_2point5, "ratingbar_2point5"),
-            new Layout(R.layout.ratingbar_5, "ratingbar_5"),
-            new Layout(R.layout.ratingbar_0, "ratingbar_0_pressed",
-                    new ViewPressedModifier()),
-            new Layout(R.layout.ratingbar_2point5, "ratingbar_2point5_pressed",
-                    new ViewPressedModifier()),
-            new Layout(R.layout.ratingbar_5, "ratingbar_5_pressed",
-                    new ViewPressedModifier()),
-            new Layout(R.layout.searchview, "searchview_query",
-                    new SearchViewModifier(SearchViewModifier.QUERY)),
-            new Layout(R.layout.searchview, "searchview_query_hint",
-                    new SearchViewModifier(SearchViewModifier.QUERY_HINT)),
-            new Layout(R.layout.seekbar_0, "seekbar_0"),
-            new Layout(R.layout.seekbar_100, "seekbar_100"),
-            new Layout(R.layout.seekbar_50, "seekbar_50"),
-            new Layout(R.layout.spinner, "spinner"),
-            new Layout(R.layout.switch_button_checked, "switch_button_checked"),
-            new Layout(R.layout.switch_button, "switch_button"),
-            new Layout(R.layout.textview, "textview"),
-            new Layout(R.layout.timepicker, "timepicker",
-                    new TimePickerModifier()),
-            new Layout(R.layout.togglebutton_checked, "togglebutton_checked"),
-            new Layout(R.layout.togglebutton, "togglebutton"),
-    };
 }
diff --git a/hostsidetests/theme/app/src/android/theme/app/ThemeInfo.java b/hostsidetests/theme/app/src/android/theme/app/ThemeInfo.java
new file mode 100644
index 0000000..6a3d4aa
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/ThemeInfo.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 android.theme.app;
+
+/**
+ * A class to encapsulate information about a theme.
+ */
+class ThemeInfo {
+    public static final int HOLO = 0;
+    public static final int MATERIAL = 1;
+
+    public final int spec;
+    public final int id;
+    public final int apiLevel;
+    public final String name;
+
+    ThemeInfo(int spec, int id, int apiLevel, String name) {
+        this.spec = spec;
+        this.id = id;
+        this.apiLevel = apiLevel;
+        this.name = name;
+    }
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java b/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java
index e9dca7a..2c71cc6 100644
--- a/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java
+++ b/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java
@@ -16,19 +16,30 @@
 
 package android.theme.app.modifiers;
 
-import android.theme.app.LayoutModifier;
 import android.view.View;
 
 /**
- * {@link LayoutModifier} that does nothing.
+ * {@link AbstractLayoutModifier} that does nothing.
  */
-abstract class AbstractLayoutModifier implements LayoutModifier {
+public abstract class AbstractLayoutModifier {
 
-    @Override
+    /**
+     * Modifies the view before it has been added to a parent. Useful for avoiding animations in
+     * response to setter calls.
+     *
+     * @param view the view inflated by the test activity
+     */
     public void modifyViewBeforeAdd(View view) {
+
     }
 
-    @Override
+    /**
+     * Modifies the view after it has been added to a parent. Useful for running animations in
+     * response to setter calls.
+     *
+     * @param view the view inflated by the test activity
+     */
     public void modifyViewAfterAdd(View view) {
+
     }
 }
diff --git a/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java b/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java
index f155fcb..58ddb43 100644
--- a/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java
+++ b/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java
@@ -16,12 +16,11 @@
 
 package android.theme.app.modifiers;
 
-import android.theme.app.LayoutModifier;
 import android.view.View;
 import android.widget.DatePicker;
 
 /**
- * {@link LayoutModifier} that sets a precise date on a {@link DatePicker}.
+ * {@link AbstractLayoutModifier} that sets a precise date on a {@link DatePicker}.
  */
 public class DatePickerModifier extends AbstractLayoutModifier {
 
diff --git a/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java b/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java
index dcd8c89..325751f 100644
--- a/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java
+++ b/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java
@@ -16,7 +16,6 @@
 
 package android.theme.app.modifiers;
 
-import android.animation.ValueAnimator;
 import android.view.View;
 import android.view.animation.Interpolator;
 import android.widget.ProgressBar;
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index 199830f..7a931a4 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -159,7 +159,7 @@
             return;
         }
 
-        assertTrue("Aborted image generation", generateDeviceImages());
+        assertTrue("Aborted image generation, see device log for details", generateDeviceImages());
 
         // Pull ZIP file from remote device.
         final File localZip = File.createTempFile("generated", ".zip");
diff --git a/hostsidetests/usage/AndroidTest.xml b/hostsidetests/usage/AndroidTest.xml
index 9ccc7e1..fc7f46e 100644
--- a/hostsidetests/usage/AndroidTest.xml
+++ b/hostsidetests/usage/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="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="CtsAppUsageTestApp.apk" />
diff --git a/hostsidetests/webkit/AndroidTest.xml b/hostsidetests/webkit/AndroidTest.xml
index 927d28f..54a6c9a 100644
--- a/hostsidetests/webkit/AndroidTest.xml
+++ b/hostsidetests/webkit/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="webview" />
     <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="CtsWebViewStartupApp.apk" />
diff --git a/tests/AlarmManager/AndroidTest.xml b/tests/AlarmManager/AndroidTest.xml
index a8c8955..f44ae93 100644
--- a/tests/AlarmManager/AndroidTest.xml
+++ b/tests/AlarmManager/AndroidTest.xml
@@ -17,6 +17,8 @@
 <configuration description="Config for CTS Alarm Manager test cases">
     <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="instant_app" />
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
index ecd9792..e528968 100644
--- a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
@@ -32,6 +32,7 @@
 import android.content.IntentFilter;
 import android.os.BatteryManager;
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -54,6 +55,7 @@
 /**
  * Tests that app standby imposes the appropriate restrictions on alarms
  */
+@AppModeFull
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class AppStandbyTests {
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java
index f36b07f..524508c 100644
--- a/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java
@@ -19,8 +19,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.alarmmanager.alarmtestapp.cts.TestAlarmScheduler;
 import android.alarmmanager.alarmtestapp.cts.TestAlarmReceiver;
+import android.alarmmanager.alarmtestapp.cts.TestAlarmScheduler;
 import android.app.AlarmManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -45,6 +46,7 @@
  * Tests that apps put in forced app standby by the user do not get to run alarms while in the
  * background
  */
+@AppModeFull
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class BackgroundRestrictedAlarmsTest {
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/InstantAppsTests.java b/tests/AlarmManager/src/android/alarmmanager/cts/InstantAppsTests.java
new file mode 100644
index 0000000..959df85
--- /dev/null
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/InstantAppsTests.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.alarmmanager.cts;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeInstant;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests that alarm manager works as expected with instant apps
+ */
+@AppModeInstant
+@RunWith(AndroidJUnit4.class)
+public class InstantAppsTests {
+    private static final String TAG = "AlarmManagerInstantTests";
+
+    private AlarmManager mAlarmManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mAlarmManager = mContext.getSystemService(AlarmManager.class);
+        assumeTrue(mContext.getPackageManager().isInstantApp());
+        updateAlarmManagerSettings();
+    }
+
+    @Test
+    public void elapsedRealtimeAlarm() throws Exception {
+        final long futurity = 2500;
+        final long triggerElapsed = SystemClock.elapsedRealtime() + futurity;
+        final CountDownLatch latch = new CountDownLatch(1);
+        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, triggerElapsed, TAG,
+                () -> latch.countDown(), null);
+        Thread.sleep(futurity);
+        assertTrue("Alarm did not fire as expected", latch.await(500, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void rtcAlarm() throws Exception {
+        final long futurity = 2500;
+        final long triggerRtc = System.currentTimeMillis() + futurity;
+        final CountDownLatch latch = new CountDownLatch(1);
+        mAlarmManager.setExact(AlarmManager.RTC, triggerRtc, TAG, () -> latch.countDown(), null);
+        Thread.sleep(futurity);
+        assertTrue("Alarm did not fire as expected", latch.await(500, TimeUnit.MILLISECONDS));
+    }
+
+    @After
+    public void deleteAlarmManagerSettings() {
+        SystemUtil.runShellCommand("settings delete global alarm_manager_constants");
+    }
+
+    private void updateAlarmManagerSettings() {
+        final StringBuffer cmd = new StringBuffer("settings put global alarm_manager_constants ");
+        cmd.append("min_futurity=0");
+        SystemUtil.runShellCommand(cmd.toString());
+    }
+}
diff --git a/tests/acceleration/Android.mk b/tests/acceleration/Android.mk
index cef4379..8ae5ddc 100644
--- a/tests/acceleration/Android.mk
+++ b/tests/acceleration/Android.mk
@@ -32,7 +32,7 @@
 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_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
 
 LOCAL_PACKAGE_NAME := CtsAccelerationTestCases
 
diff --git a/tests/acceleration/AndroidManifest.xml b/tests/acceleration/AndroidManifest.xml
index 1a21554..27ff97a 100644
--- a/tests/acceleration/AndroidManifest.xml
+++ b/tests/acceleration/AndroidManifest.xml
@@ -15,7 +15,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="android.acceleration.cts">
+          package="android.acceleration.cts"
+          android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
diff --git a/tests/acceleration/AndroidTest.xml b/tests/acceleration/AndroidTest.xml
index b28f845..68eb78f 100644
--- a/tests/acceleration/AndroidTest.xml
+++ b/tests/acceleration/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS Acceleration test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="location" />
+    <option name="config-descriptor:metadata" key="parameter" value="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="CtsAccelerationTestCases.apk" />
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 029dc51..8fbc3a2 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -81,7 +81,7 @@
         </service>
 
         <service
-                android:name=".AccessibilityGestureDetectorTest$StubService"
+                android:name=".GestureDetectionStubAccessibilityService"
                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
             <intent-filter>
                 <action android:name="android.accessibilityservice.AccessibilityService" />
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 27ec20b..b1a4352 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -47,29 +47,23 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
-
-/**
- * Verify that motion events are recognized as accessibility gestures.
- */
+/** Verify that motion events are recognized as accessibility gestures. */
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityGestureDetectorTest {
 
     // Constants
-    static final float GESTURE_LENGTH_INCHES = 1.0f;
-    static final long STROKE_MS = 400;
-    static final long GESTURE_DISPATCH_TIMEOUT_MS = 3000;
-    static final long GESTURE_RECOGNIZE_TIMEOUT_MS = 3000;
-    static final long EVENT_DISPATCH_TIMEOUT_MS = 3000;
-    static final long EVENT_RECOGNIZE_TIMEOUT_MS = 3000;
+    private static final float GESTURE_LENGTH_INCHES = 1.0f;
+    private static final long STROKE_MS = 400;
+    private static final long GESTURE_DISPATCH_TIMEOUT_MS = 3000;
+    private static final long EVENT_DISPATCH_TIMEOUT_MS = 3000;
 
-    // Member variables
-    StubService mService;  // Test AccessibilityService that collects gestures.
+    // Test AccessibilityService that collects gestures.
+    GestureDetectionStubAccessibilityService mService; 
     boolean mHasTouchScreen;
     boolean mScreenBigEnough;
-    int mStrokeLenPxX;  // Gesture stroke size, in pixels
+    int mStrokeLenPxX; // Gesture stroke size, in pixels
     int mStrokeLenPxY;
-    Point mCenter;  // Center of screen. Gestures all start from this point.
+    Point mCenter; // Center of screen. Gestures all start from this point.
     PointF mTapLocation;
     @Mock AccessibilityService.GestureResultCallback mGestureDispatchCallback;
 
@@ -94,16 +88,14 @@
         windowManager.getDefaultDisplay().getRealMetrics(metrics);
         mCenter = new Point((int) metrics.widthPixels / 2, (int) metrics.heightPixels / 2);
         mTapLocation = new PointF(mCenter);
-        mStrokeLenPxX = (int)(GESTURE_LENGTH_INCHES * metrics.xdpi);
-        mStrokeLenPxY = (int)(GESTURE_LENGTH_INCHES * metrics.ydpi);
-        mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES)
-                && (metrics.heightPixels / (2 * metrics.ydpi) > GESTURE_LENGTH_INCHES);
+        mStrokeLenPxX = (int) (GESTURE_LENGTH_INCHES * metrics.xdpi);
+        mStrokeLenPxY = (int) (GESTURE_LENGTH_INCHES * metrics.ydpi);
+        mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES);
         if (!mScreenBigEnough) {
             return;
         }
-
         // Start stub accessibility service.
-        mService = StubService.enableSelf(instrumentation);
+        mService = GestureDetectionStubAccessibilityService.enableSelf(instrumentation);
     }
 
     @After
@@ -165,7 +157,7 @@
         long pathDurationMs = numPathSegments * STROKE_MS;
         GestureDescription gesture = new GestureDescription.Builder()
                 .addStroke(new StrokeDescription(
-                        linePath(mCenter, delta1, delta2), 0, pathDurationMs, false))
+                linePath(mCenter, delta1, delta2), 0, pathDurationMs, false))
                 .build();
 
         // Dispatch gesture motions.
@@ -174,9 +166,8 @@
         // sendPointerSync() injects events.
         mService.clearGestures();
         mService.runOnServiceSync(() ->
-                mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
-        verify(mGestureDispatchCallback,
-                timeout(GESTURE_DISPATCH_TIMEOUT_MS).atLeastOnce())
+        mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
+        verify(mGestureDispatchCallback, timeout(GESTURE_DISPATCH_TIMEOUT_MS).atLeastOnce())
                 .onCompleted(any());
 
         // Wait for gesture recognizer, and check recognized gesture.
@@ -225,15 +216,14 @@
     /** Test touch for accessibility events */
     private void assertEventAfterGesture(GestureDescription gesture, int... events) {
         mService.clearEvents();
-        mService.runOnServiceSync(() ->
-                mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
-        verify(mGestureDispatchCallback,
-                timeout(EVENT_DISPATCH_TIMEOUT_MS).atLeastOnce())
+        mService.runOnServiceSync(
+                () -> mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
+        verify(mGestureDispatchCallback, timeout(EVENT_DISPATCH_TIMEOUT_MS).atLeastOnce())
                 .onCompleted(any());
 
         mService.waitUntilEvent(events.length);
         assertEquals(events.length, mService.getEventsSize());
-        for (int i = 0 ; i < events.length ; i++) {
+        for (int i = 0; i < events.length; i++) {
             assertEquals(events[i], mService.getEvent(i));
         }
     }
@@ -270,107 +260,4 @@
         builder.addStroke(tap2);
         return builder.build();
     }
-
-    /** Acessibility service stub, which will collect recognized gestures. */
-    public static class StubService extends InstrumentedAccessibilityService {
-        private final Object mLock = new Object();
-        private ArrayList<Integer> mCollectedGestures = new ArrayList();
-        private ArrayList<Integer> mCollectedEvents = new ArrayList();
-
-        public static StubService enableSelf(Instrumentation instrumentation) {
-            return InstrumentedAccessibilityService.enableService(
-                    instrumentation, StubService.class);
-        }
-
-        @Override
-        protected boolean onGesture(int gestureId) {
-            synchronized (mCollectedGestures) {
-                mCollectedGestures.add(gestureId);
-                mCollectedGestures.notifyAll();  // Stop waiting for gesture.
-            }
-            return true;
-        }
-
-        public void clearGestures() {
-            synchronized (mCollectedGestures) {
-                mCollectedGestures.clear();
-            }
-        }
-
-        public int getGesturesSize() {
-            synchronized (mCollectedGestures) {
-                return mCollectedGestures.size();
-            }
-        }
-
-        public int getGesture(int index) {
-            synchronized (mCollectedGestures) {
-                return mCollectedGestures.get(index);
-            }
-        }
-
-        /** Wait for onGesture() to collect next gesture. */
-        public void waitUntilGesture() {
-            synchronized (mCollectedGestures) {
-                if (mCollectedGestures.size() > 0) {
-                  return;
-                }
-                try {
-                    mCollectedGestures.wait(GESTURE_RECOGNIZE_TIMEOUT_MS);
-                } catch (InterruptedException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        }
-
-        @Override
-        public void onAccessibilityEvent(AccessibilityEvent event) {
-            synchronized (mLock) {
-                switch (event.getEventType()) {
-                    case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
-                        mCollectedEvents.add(event.getEventType());
-                        mLock.notifyAll();
-                        break;
-                    case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
-                    case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
-                    case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
-                        mCollectedEvents.add(event.getEventType());
-                }
-            }
-            super.onAccessibilityEvent(event);
-        }
-
-        public void clearEvents() {
-            synchronized (mLock) {
-                mCollectedEvents.clear();
-            }
-        }
-
-        public int getEventsSize() {
-            synchronized (mLock) {
-                return mCollectedEvents.size();
-            }
-        }
-
-        public int getEvent(int index) {
-            synchronized (mLock) {
-                return mCollectedEvents.get(index);
-            }
-        }
-
-        /** Wait for onAccessibilityEvent() to collect next gesture. */
-        public void waitUntilEvent(int count) {
-            synchronized (mLock) {
-                if (mCollectedEvents.size() >= count) {
-                    return;
-                }
-                try {
-                    mLock.wait(EVENT_RECOGNIZE_TIMEOUT_MS);
-                } catch (InterruptedException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        }
-    }
-
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java
new file mode 100644
index 0000000..63601cd
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java
@@ -0,0 +1,125 @@
+/**
+ * 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.accessibilityservice.cts;
+
+import android.app.Instrumentation;
+import android.view.accessibility.AccessibilityEvent;
+import java.util.ArrayList;
+
+/** Accessibility service stub, which will collect recognized gestures. */
+public class GestureDetectionStubAccessibilityService extends InstrumentedAccessibilityService {
+    private static final long GESTURE_RECOGNIZE_TIMEOUT_MS = 3000;
+    private static final long EVENT_RECOGNIZE_TIMEOUT_MS = 3000;
+    // Member variables
+    private final Object mLock = new Object();
+    private ArrayList<Integer> mCollectedGestures = new ArrayList();
+    private ArrayList<Integer> mCollectedEvents = new ArrayList();
+
+    public static GestureDetectionStubAccessibilityService enableSelf(
+            Instrumentation instrumentation) {
+        return InstrumentedAccessibilityService.enableService(
+                instrumentation, GestureDetectionStubAccessibilityService.class);
+    }
+
+    @Override
+    protected boolean onGesture(int gestureId) {
+        synchronized (mCollectedGestures) {
+            mCollectedGestures.add(gestureId);
+            mCollectedGestures.notifyAll(); // Stop waiting for gesture.
+        }
+        return true;
+    }
+
+    public void clearGestures() {
+        synchronized (mCollectedGestures) {
+            mCollectedGestures.clear();
+        }
+    }
+
+    public int getGesturesSize() {
+        synchronized (mCollectedGestures) {
+            return mCollectedGestures.size();
+        }
+    }
+
+    public int getGesture(int index) {
+        synchronized (mCollectedGestures) {
+            return mCollectedGestures.get(index);
+        }
+    }
+
+    /** Wait for onGesture() to collect next gesture. */
+    public void waitUntilGesture() {
+        synchronized (mCollectedGestures) {
+            if (mCollectedGestures.size() > 0) {
+                return;
+            }
+            try {
+                mCollectedGestures.wait(GESTURE_RECOGNIZE_TIMEOUT_MS);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        synchronized (mLock) {
+            switch (event.getEventType()) {
+                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
+                    mCollectedEvents.add(event.getEventType());
+                    mLock.notifyAll();
+                    break;
+                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
+                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
+                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
+                    mCollectedEvents.add(event.getEventType());
+            }
+        }
+        super.onAccessibilityEvent(event);
+    }
+
+    public void clearEvents() {
+        synchronized (mLock) {
+            mCollectedEvents.clear();
+        }
+    }
+
+    public int getEventsSize() {
+        synchronized (mLock) {
+            return mCollectedEvents.size();
+        }
+    }
+
+    public int getEvent(int index) {
+        synchronized (mLock) {
+            return mCollectedEvents.get(index);
+        }
+    }
+
+    /** Wait for onAccessibilityEvent() to collect next gesture. */
+    public void waitUntilEvent(int count) {
+        synchronized (mLock) {
+            if (mCollectedEvents.size() >= count) {
+                return;
+            }
+            try {
+                mLock.wait(EVENT_RECOGNIZE_TIMEOUT_MS);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
index c0b10fe..f99f8bf 100644
--- a/tests/admin/AndroidTest.xml
+++ b/tests/admin/AndroidTest.xml
@@ -22,6 +22,10 @@
     <!-- Not testing features backed by native code, so only need to run against one ABI -->
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
 
+    <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
+        <option name="user-type" value="system" />
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="install-arg" value="-t" />
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 9298ac2..349578f 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -861,6 +861,19 @@
         }
     }
 
+    public void testSetDefaultSmsApplication_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetDefaultSmsApplication_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setDefaultSmsApplication(mComponent, "android.admin.cts");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
     public void testCreateAdminSupportIntent_returnNullIfRestrictionIsNotSet() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testCreateAdminSupportIntent");
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 7f66a12..9ef2f3d 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -372,6 +372,16 @@
             </intent-filter>
         </service>
 
+        <service android:name="android.app.stubs.TestTileService"
+                 android:exported="true"
+                 android:label="TestTileService"
+                 android:icon="@drawable/robot"
+                 android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
+            <intent-filter>
+                <action android:name="android.service.quicksettings.action.QS_TILE" />
+            </intent-filter>
+        </service>
+
         <activity android:name="android.app.stubs.AutomaticZenRuleActivity">
             <intent-filter>
                 <action android:name="android.app.action.AUTOMATIC_ZEN_RULE" />
diff --git a/tests/app/app/src/android/app/stubs/TestTileService.java b/tests/app/app/src/android/app/stubs/TestTileService.java
new file mode 100644
index 0000000..d3c6db4
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestTileService.java
@@ -0,0 +1,68 @@
+/*
+ * 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.app.stubs;
+
+import android.content.ComponentName;
+import android.os.Debug;
+import android.service.quicksettings.TileService;
+
+public class TestTileService extends TileService {
+
+    public static final String TAG = "TestTileService";
+    public static final String PKG = "android.app.stubs";
+    public static final int ICON_ID = R.drawable.robot;
+
+    private static TestTileService sTestTileService = null;
+    boolean isConnected;
+
+    public static String getId() {
+        return String.format("%s/%s", TestTileService.class.getPackage().getName(),
+                TestTileService.class.getName());
+    }
+
+    public static ComponentName getComponentName() {
+        return new ComponentName(TestTileService.class.getPackage().getName(),
+                TestTileService.class.getName());
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    public static TileService getInstance() {
+        return sTestTileService;
+    }
+
+    public boolean isConnected() {
+        return isConnected;
+    }
+
+    @Override
+    public void onTileAdded() {
+        super.onTileAdded();
+        sTestTileService = this;
+        isConnected = true;
+    }
+
+    @Override
+    public void onTileRemoved() {
+        super.onTileRemoved();
+        isConnected = false;
+        sTestTileService = null;
+    }
+}
diff --git a/tests/app/src/android/app/cts/AdjustmentTest.java b/tests/app/src/android/app/cts/AdjustmentTest.java
new file mode 100644
index 0000000..8d65d3d
--- /dev/null
+++ b/tests/app/src/android/app/cts/AdjustmentTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.app.cts;
+
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.service.notification.Adjustment;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class AdjustmentTest extends AndroidTestCase {
+    private static final String ADJ_PACKAGE = "com.foo.bar";
+    private static final String ADJ_KEY = "foo_key";
+    private static final String ADJ_EXPLANATION = "I just feel like adjusting this";
+    private static final int ADJ_USER = 47;
+
+    private final Bundle mSignals = new Bundle();
+
+    private Adjustment mAdjustment;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mSignals.putString("foobar", "Hello, world!");
+        mSignals.putInt("chirp", 47);
+        mAdjustment = new Adjustment(ADJ_PACKAGE, ADJ_KEY, mSignals, ADJ_EXPLANATION, ADJ_USER);
+    }
+
+    public void testGetPackage() {
+        assertEquals(ADJ_PACKAGE, mAdjustment.getPackage());
+    }
+
+    public void testGetKey() {
+        assertEquals(ADJ_KEY, mAdjustment.getKey());
+    }
+
+    public void testGetExplanation() {
+        assertEquals(ADJ_EXPLANATION, mAdjustment.getExplanation());
+    }
+
+    public void testGetUser() {
+        assertEquals(ADJ_USER, mAdjustment.getUser());
+    }
+
+    public void testGetSignals() {
+        assertEquals(mSignals, mAdjustment.getSignals());
+        assertEquals("Hello, world!", mAdjustment.getSignals().getString("foobar"));
+        assertEquals(47, mAdjustment.getSignals().getInt("chirp"));
+    }
+
+    public void testDescribeContents() {
+        assertEquals(0, mAdjustment.describeContents());
+    }
+
+    public void testParcelling() {
+        final Parcel outParcel = Parcel.obtain();
+        mAdjustment.writeToParcel(outParcel, 0);
+        outParcel.setDataPosition(0);
+        final Adjustment unparceled = Adjustment.CREATOR.createFromParcel(outParcel);
+
+        assertEquals(mAdjustment.getPackage(), unparceled.getPackage());
+        assertEquals(mAdjustment.getKey(), unparceled.getKey());
+        assertEquals(mAdjustment.getExplanation(), unparceled.getExplanation());
+        assertEquals(mAdjustment.getUser(), unparceled.getUser());
+
+        assertEquals("Hello, world!", unparceled.getSignals().getString("foobar"));
+        assertEquals(47, unparceled.getSignals().getInt("chirp"));
+    }
+}
diff --git a/tests/app/src/android/app/cts/ConditionTest.java b/tests/app/src/android/app/cts/ConditionTest.java
index b1985d1..1b578f0 100644
--- a/tests/app/src/android/app/cts/ConditionTest.java
+++ b/tests/app/src/android/app/cts/ConditionTest.java
@@ -67,4 +67,47 @@
         assertEquals(-1, condition1.icon);
         assertEquals(Condition.FLAG_RELEVANT_ALWAYS, condition1.flags);
     }
+
+    public void testCopy() {
+        Condition condition = new Condition(mConditionId, mSummary, mState);
+        Condition condition1 = condition.copy();
+        assertEquals(mConditionId, condition1.id);
+        assertEquals(mSummary, condition1.summary);
+        assertEquals("", condition1.line1);
+        assertEquals("", condition1.line2);
+        assertEquals(mState, condition1.state);
+        assertEquals(-1, condition1.icon);
+        assertEquals(Condition.FLAG_RELEVANT_ALWAYS, condition1.flags);
+    }
+
+    public void testIsValidId_null() {
+        assertFalse(Condition.isValidId(null, null));
+    }
+
+    public void testIsValidId_noScheme() {
+        String pkg = this.getClass().getPackage().toString();
+        Uri uri = new Uri.Builder().authority(pkg).build();
+        assertFalse(Condition.isValidId(uri, pkg));
+    }
+
+    public void testIsValidId_wrongAuthority() {
+        String pkg = this.getClass().getPackage().toString();
+        Uri uri = new Uri.Builder().authority(pkg).scheme(Condition.SCHEME).build();
+        assertFalse(Condition.isValidId(uri, "different"));
+    }
+
+    public void testIsValidId() {
+        String pkg = this.getClass().getPackage().toString();
+        Uri uri = new Uri.Builder().authority(pkg).scheme(Condition.SCHEME).build();
+        assertTrue(Condition.isValidId(uri, pkg));
+    }
+
+    public void testNewId() {
+        assertTrue(Condition.isValidId(
+                Condition.newId(mContext).build(), mContext.getPackageName()));
+    }
+
+    public void testRelevanceToString() {
+        assertNotNull(Condition.relevanceToString(Condition.FLAG_RELEVANT_ALWAYS));
+    }
 }
diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index 76cd58c..98533ac 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -470,6 +470,8 @@
             receiver.waitForDownloadComplete(SHORT_TIMEOUT, downloadId);
             assertSuccessfulDownload(downloadId, downloadLocation);
             final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(downloadId);
+            mContext.grantUriPermission("com.android.shell", downloadUri,
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION);
             final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
             final ContentResolver contentResolver = mContext.getContentResolver();
             assertArrayEquals(hash(contentResolver.openInputStream(downloadUri)),
@@ -502,6 +504,8 @@
                 "text/plain", downloadFile.getPath(), fileContents.getBytes().length, true);
         assertTrue(downloadId >= 0);
         final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(downloadId);
+        mContext.grantUriPermission("com.android.shell", downloadUri,
+                Intent.FLAG_GRANT_READ_URI_PERMISSION);
         final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
         assertArrayEquals(hash(new FileInputStream(downloadFile)),
                 hash(mContext.getContentResolver().openInputStream(mediaStoreUri)));
@@ -555,6 +559,8 @@
             assertEquals(testTitle, cursor.getString(0));
         }
 
+        mContext.grantUriPermission("com.android.shell", downloadUri,
+                Intent.FLAG_GRANT_READ_URI_PERMISSION);
         final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
         final String newTitle = "New_title";
         updateUri(mediaStoreUri, "_display_name", newTitle);
diff --git a/tests/app/src/android/app/cts/NotificationCarExtenderTest.java b/tests/app/src/android/app/cts/NotificationCarExtenderTest.java
new file mode 100644
index 0000000..20bf336
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationCarExtenderTest.java
@@ -0,0 +1,138 @@
+ /*
+ * 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.app.cts;
+
+import android.app.Notification;
+import android.app.Notification.CarExtender;
+import android.app.Notification.CarExtender.Builder;
+import android.app.Notification.CarExtender.UnreadConversation;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.test.AndroidTestCase;
+
+public class NotificationCarExtenderTest extends AndroidTestCase {
+
+    private Context mContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getContext();
+    }
+
+    public void testCarExtender_EmptyConstructor() {
+        CarExtender extender = new Notification.CarExtender();
+        assertNotNull(extender);
+        assertEquals(Notification.COLOR_DEFAULT, extender.getColor());
+        assertEquals(null, extender.getLargeIcon());
+        assertEquals(null, extender.getUnreadConversation());
+    }
+
+    public void testCarExtender_Constructor() {
+        Notification notification = new Notification();
+        CarExtender extender = new Notification.CarExtender(notification);
+        assertNotNull(extender);
+        assertEquals(Notification.COLOR_DEFAULT, extender.getColor());
+        assertEquals(null, extender.getLargeIcon());
+        assertEquals(null, extender.getUnreadConversation());
+    }
+
+    public void testCarExtender() {
+        final int testColor = 11;
+        final Bitmap testIcon = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        final UnreadConversation testConversation =
+            new Builder("testParticipant")
+                .addMessage("testMessage")
+                .setLatestTimestamp(System.currentTimeMillis())
+                .build();
+
+        CarExtender extender = new Notification.CarExtender()
+            .setColor(testColor)
+            .setLargeIcon(testIcon)
+            .setUnreadConversation(testConversation);
+
+        assertEquals(testColor, extender.getColor());
+        assertEquals(testIcon, extender.getLargeIcon());
+        assertEquals(testConversation, extender.getUnreadConversation());
+    }
+
+    public void testCarExtender_extend() {
+        final int testColor = 11;
+        final Bitmap testIcon = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        final UnreadConversation testConversation =
+            new Builder("testParticipant")
+                .addMessage("testMessage")
+                .setLatestTimestamp(System.currentTimeMillis())
+                .build();
+        Notification.Builder notifBuilder = new Notification.Builder(mContext, "test id")
+            .setSmallIcon(1);
+        CarExtender extender = new Notification.CarExtender()
+            .setColor(testColor)
+            .setLargeIcon(testIcon)
+            .setUnreadConversation(testConversation);
+
+        extender.extend(notifBuilder);
+
+        Notification notification = notifBuilder.build();
+
+        CarExtender receiveCarExtender = new CarExtender(notification);
+
+        assertNotNull(receiveCarExtender);
+        assertEquals(testColor, receiveCarExtender.getColor());
+        assertEquals(testIcon, receiveCarExtender.getLargeIcon());
+        assertEquals(1, receiveCarExtender.getUnreadConversation().getMessages().length);
+        assertEquals(testConversation.getMessages().length,
+            receiveCarExtender.getUnreadConversation().getMessages().length);
+        assertEquals(testConversation.getMessages()[0],
+            receiveCarExtender.getUnreadConversation().getMessages()[0]);
+    }
+
+    public void testCarExtender_UnreadConversationAndBuilder() {
+        final long testTime = System.currentTimeMillis();
+        final String testMessage = "testMessage";
+        final String testParticipant = "testParticipant";
+        final Intent testIntent = new Intent("testIntent");
+        final PendingIntent testPendingIntent =
+            PendingIntent.getBroadcast(mContext, 0, testIntent,
+            PendingIntent.FLAG_CANCEL_CURRENT);
+        final PendingIntent testReplyPendingIntent =
+            PendingIntent.getBroadcast(mContext, 0, testIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        final RemoteInput testRemoteInput = new RemoteInput.Builder("key").build();
+
+        final UnreadConversation testConversation =
+            new Builder(testParticipant)
+                .setLatestTimestamp(testTime)
+                .addMessage(testMessage)
+                .setReadPendingIntent(testPendingIntent)
+                .setReplyAction(testReplyPendingIntent, testRemoteInput)
+                .build();
+
+        assertEquals(testTime, testConversation.getLatestTimestamp());
+        assertEquals(1, testConversation.getMessages().length);
+        assertEquals(testMessage, testConversation.getMessages()[0]);
+        assertEquals(testParticipant, testConversation.getParticipant());
+        assertEquals(1, testConversation.getParticipants().length);
+        assertEquals(testParticipant, testConversation.getParticipants()[0]);
+        assertEquals(testPendingIntent, testConversation.getReadPendingIntent());
+        assertEquals(testRemoteInput, testConversation.getRemoteInput());
+        assertEquals(testPendingIntent, testConversation.getReplyPendingIntent());
+    }
+}
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index f2b5cd4..cff8dcb 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -159,15 +159,11 @@
         NotificationChannel channel =
                 new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
         channel.setAllowBubbles(true);
-        assertEquals("Only HIGH channels can have bubbles", false, channel.canBubble());
+        assertEquals(true, channel.canBubble());
 
-        channel = new NotificationChannel("1", "one", IMPORTANCE_HIGH);
+        channel = new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
         channel.setAllowBubbles(false);
         assertEquals(false, channel.canBubble());
-
-        channel = new NotificationChannel("1", "one", IMPORTANCE_HIGH);
-        channel.setAllowBubbles(true);
-        assertEquals(true, channel.canBubble());
     }
 
     public void testIsImportanceLockedByOEM() {
diff --git a/tests/app/src/android/app/cts/NotificationDecoratedCustomViewStyleTest.java b/tests/app/src/android/app/cts/NotificationDecoratedCustomViewStyleTest.java
new file mode 100644
index 0000000..4a1497f
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationDecoratedCustomViewStyleTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.app.cts;
+
+import android.app.Notification.DecoratedCustomViewStyle;
+import android.app.Notification.DecoratedMediaCustomViewStyle;
+import android.test.AndroidTestCase;
+
+public class NotificationDecoratedCustomViewStyleTest extends AndroidTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testNotificationDecoratedCustomViewStyle_Constructor() {
+        DecoratedCustomViewStyle customViewStyle = new DecoratedCustomViewStyle();
+        assertNotNull(customViewStyle);
+    }
+
+    public void testNotificationDecoratedMediaCustomViewStyle_Constructor() {
+        DecoratedMediaCustomViewStyle customViewStyle = new DecoratedMediaCustomViewStyle();
+        assertNotNull(customViewStyle);
+    }
+}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index f639d56..9949b56 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -85,6 +85,8 @@
 import java.util.Objects;
 import java.util.UUID;
 
+/* This tests NotificationListenerService together with NotificationManager, as you need to have
+ * notifications to manipulate in order to test the listener service. */
 public class NotificationManagerTest extends AndroidTestCase {
     final String TAG = NotificationManagerTest.class.getSimpleName();
     final boolean DEBUG = false;
@@ -965,6 +967,240 @@
         mListener.resetData();
     }
 
+    public void testCanBubble_ranking() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        assertEquals(1, Settings.Secure.getInt(
+                mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BUBBLES));
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        assertNotNull(mListener);
+        try {
+            sendNotification(1, R.drawable.black);
+            Thread.sleep(500); // wait for notification listener to receive notification
+            NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+            NotificationListenerService.Ranking outRanking =
+                    new NotificationListenerService.Ranking();
+            for (String key : rankingMap.getOrderedKeys()) {
+                if (key.contains(mListener.getPackageName())) {
+                    rankingMap.getRanking(key, outRanking);
+                    // by default everything can bubble
+                    assertTrue(outRanking.canBubble());
+                }
+            }
+
+            // turn off bubbles globally
+            SystemUtil.runWithShellPermissionIdentity(() ->
+                    Settings.Secure.putInt(mContext.getContentResolver(),
+                            Settings.Secure.NOTIFICATION_BUBBLES, 0));
+
+            Thread.sleep(500); // wait for ranking update
+
+            rankingMap = mListener.mRankingMap;
+            outRanking = new NotificationListenerService.Ranking();
+            for (String key : rankingMap.getOrderedKeys()) {
+                if (key.contains(mListener.getPackageName())) {
+                    assertFalse(outRanking.canBubble());
+                }
+            }
+
+            mListener.resetData();
+        } finally {
+            SystemUtil.runWithShellPermissionIdentity(() ->
+                    Settings.Secure.putInt(mContext.getContentResolver(),
+                            Settings.Secure.NOTIFICATION_BUBBLES, 1));
+        }
+    }
+
+    public void testShowBadging_ranking() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        final int originalBadging = Settings.Secure.getInt(
+                mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BADGING);
+
+        SystemUtil.runWithShellPermissionIdentity(() ->
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.NOTIFICATION_BADGING, 1));
+        assertEquals(1, Settings.Secure.getInt(
+                mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BADGING));
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        assertNotNull(mListener);
+        try {
+            sendNotification(1, R.drawable.black);
+            Thread.sleep(500); // wait for notification listener to receive notification
+            NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+            NotificationListenerService.Ranking outRanking =
+                    new NotificationListenerService.Ranking();
+            for (String key : rankingMap.getOrderedKeys()) {
+                if (key.contains(mListener.getPackageName())) {
+                    rankingMap.getRanking(key, outRanking);
+                    assertTrue(outRanking.canShowBadge());
+                }
+            }
+
+            // turn off badging globally
+            SystemUtil.runWithShellPermissionIdentity(() ->
+                    Settings.Secure.putInt(mContext.getContentResolver(),
+                            Settings.Secure.NOTIFICATION_BADGING, 0));
+
+            Thread.sleep(500); // wait for ranking update
+
+            rankingMap = mListener.mRankingMap;
+            outRanking = new NotificationListenerService.Ranking();
+            for (String key : rankingMap.getOrderedKeys()) {
+                if (key.contains(mListener.getPackageName())) {
+                    assertFalse(outRanking.canShowBadge());
+                }
+            }
+
+            mListener.resetData();
+        } finally {
+            SystemUtil.runWithShellPermissionIdentity(() ->
+                    Settings.Secure.putInt(mContext.getContentResolver(),
+                            Settings.Secure.NOTIFICATION_BADGING, originalBadging));
+        }
+    }
+
+    public void testGetSuppressedVisualEffectsOff_ranking() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        assertNotNull(mListener);
+
+        final int notificationId = 1;
+        sendNotification(notificationId, R.drawable.black);
+        Thread.sleep(500); // wait for notification listener to receive notification
+
+        NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+        NotificationListenerService.Ranking outRanking =
+                new NotificationListenerService.Ranking();
+
+        for (String key : rankingMap.getOrderedKeys()) {
+            if (key.contains(mListener.getPackageName())) {
+                rankingMap.getRanking(key, outRanking);
+
+                // check notification key match
+                assertEquals(0, outRanking.getSuppressedVisualEffects());
+            }
+        }
+    }
+
+    public void testGetSuppressedVisualEffects_ranking() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        final int originalFilter = mNotificationManager.getCurrentInterruptionFilter();
+        try {
+            toggleListenerAccess(TestNotificationListener.getId(),
+                    InstrumentationRegistry.getInstrumentation(), true);
+            Thread.sleep(500); // wait for listener to be allowed
+
+            mListener = TestNotificationListener.getInstance();
+            assertNotNull(mListener);
+
+            toggleNotificationPolicyAccess(mContext.getPackageName(),
+                    InstrumentationRegistry.getInstrumentation(), true);
+            if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
+                mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0,
+                        SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK));
+            } else {
+                mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0,
+                        SUPPRESSED_EFFECT_SCREEN_ON));
+            }
+            mNotificationManager.setInterruptionFilter(
+                    NotificationManager.INTERRUPTION_FILTER_PRIORITY);
+
+            final int notificationId = 1;
+            // update notification
+            sendNotification(notificationId, R.drawable.black);
+            Thread.sleep(500); // wait for notification listener to receive notification
+
+            NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+            NotificationListenerService.Ranking outRanking =
+                    new NotificationListenerService.Ranking();
+
+            for (String key : rankingMap.getOrderedKeys()) {
+                if (key.contains(mListener.getPackageName())) {
+                    rankingMap.getRanking(key, outRanking);
+
+                    if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
+                        assertEquals(SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK,
+                                outRanking.getSuppressedVisualEffects());
+                    } else {
+                        assertEquals(SUPPRESSED_EFFECT_SCREEN_ON,
+                                outRanking.getSuppressedVisualEffects());
+                    }
+                }
+            }
+        } finally {
+            // reset notification policy
+            mNotificationManager.setInterruptionFilter(originalFilter);
+        }
+
+    }
+
+    public void testKeyChannelGroupOverrideImportanceExplanation_ranking() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        assertNotNull(mListener);
+
+        final int notificationId = 1;
+        sendNotification(notificationId, R.drawable.black);
+        Thread.sleep(500); // wait for notification listener to receive notification
+
+        NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+        NotificationListenerService.Ranking outRanking =
+                new NotificationListenerService.Ranking();
+
+        StatusBarNotification sbn = findPostedNotification(notificationId);
+
+        // check that the key and channel ids are the same in the ranking as the posted notification
+        for (String key : rankingMap.getOrderedKeys()) {
+            if (key.contains(mListener.getPackageName())) {
+                rankingMap.getRanking(key, outRanking);
+
+                // check notification key match
+                assertEquals(sbn.getKey(), outRanking.getKey());
+
+                // check notification channel ids match
+                assertEquals(sbn.getNotification().getChannelId(), outRanking.getChannel().getId());
+
+                // check override group key match
+                assertEquals(sbn.getOverrideGroupKey(), outRanking.getOverrideGroupKey());
+
+                // check importance explanation isn't null
+                assertNotNull(outRanking.getImportanceExplanation());
+            }
+        }
+    }
+
     public void testNotify_blockedChannel() throws Exception {
         mNotificationManager.cancelAll();
 
@@ -1663,4 +1899,11 @@
         SystemUtil.runWithShellPermissionIdentity(() ->
                 assertTrue(mNotificationManager.matchesCallFilter(peopleExtras)));
     }
+
+    /* Confirm that the optional methods of TestNotificationListener still exist and
+     * don't fail. */
+    public void testNotificationListenerMethods() {
+        NotificationListenerService listener = new TestNotificationListener();
+        listener.onStatusBarIconsBehaviorChanged(false);
+    }
 }
diff --git a/tests/app/src/android/app/cts/NotificationStatsTest.java b/tests/app/src/android/app/cts/NotificationStatsTest.java
new file mode 100644
index 0000000..6e3d34c
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationStatsTest.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.app.cts;
+
+import android.service.notification.NotificationStats;
+import android.test.AndroidTestCase;
+
+
+/** Test the public NotificationStats api. */
+public class NotificationStatsTest extends AndroidTestCase {
+
+    public void testGetDismissalSentiment() {
+        NotificationStats notificationStats = new NotificationStats();
+
+        // Starts at unknown. Cycle through all of the options and back.
+        assertEquals(NotificationStats.DISMISS_SENTIMENT_UNKNOWN,
+                notificationStats.getDismissalSentiment());
+        notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEGATIVE);
+        assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE,
+                notificationStats.getDismissalSentiment());
+        notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
+        assertEquals(NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
+                notificationStats.getDismissalSentiment());
+        notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_POSITIVE);
+        assertEquals(NotificationStats.DISMISS_SENTIMENT_POSITIVE,
+                notificationStats.getDismissalSentiment());
+        notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_UNKNOWN);
+        assertEquals(NotificationStats.DISMISS_SENTIMENT_UNKNOWN,
+                notificationStats.getDismissalSentiment());
+    }
+
+}
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 3109a0e..94af896 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -188,7 +188,20 @@
         assertFeature(manualPostProcessing,
                 PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
         assertFeature(raw, PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
-        assertFeature(motionTracking, PackageManager.FEATURE_CAMERA_AR);
+        if (!motionTracking) {
+          // FEATURE_CAMERA_AR requires the presence of
+          // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING but
+          // MOTION_TRACKING does not require the presence of FEATURE_CAMERA_AR
+          //
+          // Logic table:
+          //    AR= F   T
+          // MT=F   Y   N
+          //   =T   Y   Y
+          //
+          // So only check the one disallowed condition: No motion tracking and FEATURE_CAMERA_AR is
+          // available
+          assertNotAvailable(PackageManager.FEATURE_CAMERA_AR);
+        }
     }
 
     private void checkFrontCamera() {
diff --git a/tests/app/src/android/app/cts/TileServiceTest.java b/tests/app/src/android/app/cts/TileServiceTest.java
new file mode 100644
index 0000000..7daab1a
--- /dev/null
+++ b/tests/app/src/android/app/cts/TileServiceTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.app.cts;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.UiAutomation;
+import android.app.stubs.TestTileService;
+import android.os.Debug;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.support.test.InstrumentationRegistry;
+import android.test.AndroidTestCase;
+
+import junit.framework.Assert;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class TileServiceTest extends AndroidTestCase {
+    final String TAG = TileServiceTest.class.getSimpleName();
+
+    private TileService mTileService;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        toggleServiceAccess(TestTileService.getComponentName().flattenToString(), false);
+        Thread.sleep(200); // wait for service to be unbound
+        assertNull(TestTileService.getInstance());
+    }
+
+    public void testCreateTileService() {
+        final TileService tileService = new TileService();
+    }
+
+    public void testLocked_deviceNotLocked() throws Exception {
+        if (!TileService.isQuickSettingsSupported()) return;
+        startTileService();
+        assertFalse(mTileService.isLocked());
+    }
+
+    public void testSecure_deviceNotSecure() throws Exception {
+        if (!TileService.isQuickSettingsSupported()) return;
+        startTileService();
+        assertFalse(mTileService.isSecure());
+    }
+
+    public void testTile_hasCorrectIcon() throws Exception {
+        if (!TileService.isQuickSettingsSupported()) return;
+        startTileService();
+        Tile tile = mTileService.getQsTile();
+        assertEquals(TestTileService.ICON_ID, tile.getIcon().getResId());
+    }
+
+    public void testShowDialog() throws Exception {
+        if (!TileService.isQuickSettingsSupported()) return;
+        Looper.prepare();
+        Dialog dialog = new AlertDialog.Builder(mContext).create();
+        startTileService();
+        clickTile(TestTileService.getComponentName().flattenToString());
+
+        mTileService.showDialog(dialog);
+
+        assertTrue(dialog.isShowing());
+        dialog.dismiss();
+    }
+
+    public void testUnlockAndRun_phoneIsUnlockedActivityIsRun() throws Exception {
+        if (!TileService.isQuickSettingsSupported()) return;
+        startTileService();
+        assertFalse(mTileService.isLocked());
+
+        TestRunnable testRunnable = new TestRunnable();
+
+        mTileService.unlockAndRun(testRunnable);
+        Thread.sleep(100); // wait for activity to run
+        assertTrue(testRunnable.hasRan);
+    }
+
+    private void startTileService() throws Exception {
+        toggleServiceAccess(TestTileService.getComponentName().flattenToString(), true);
+        Thread.sleep(200); // wait for service to be bound
+        mTileService = TestTileService.getInstance();
+        assertNotNull(mTileService);
+    }
+
+    private void toggleServiceAccess(String componentName, boolean on) throws Exception {
+
+        String command = " cmd statusbar " + (on ? "add-tile " : "remove-tile ")
+                + componentName;
+
+        runCommand(command);
+    }
+
+    private void clickTile(String componentName) throws Exception {
+        runCommand(" cmd statusbar click-tile " + componentName);
+    }
+
+    private void runCommand(String command) throws IOException {
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        // Execute command
+        try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
+            Assert.assertNotNull("Failed to execute shell command: " + command, fd);
+            // Wait for the command to finish by reading until EOF
+            try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
+                byte[] buffer = new byte[4096];
+                while (in.read(buffer) > 0) {}
+            } catch (IOException e) {
+                throw new IOException("Could not read stdout of command: " + command, e);
+            }
+        } finally {
+            uiAutomation.destroy();
+        }
+    }
+
+    class TestRunnable implements Runnable {
+        boolean hasRan = false;
+
+        @Override
+        public void run() {
+            hasRan = true;
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
index cc1d479..1bd90a5 100644
--- a/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -243,6 +243,63 @@
         assertDesiredDimension(new Point(w, min.y / 2), new Point(w, min.y / 2));
     }
 
+    @Test
+    public void wallpaperColors_primary() {
+        Bitmap tmpWallpaper = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(tmpWallpaper);
+        canvas.drawColor(Color.RED);
+
+        try {
+            mWallpaperManager.setBitmap(tmpWallpaper);
+            WallpaperColors colors = mWallpaperManager.getWallpaperColors(
+                    WallpaperManager.FLAG_SYSTEM);
+
+            // Check that primary color is almost red
+            Color primary = colors.getPrimaryColor();
+            final float delta = 0.1f;
+            Assert.assertEquals("red", 1f, primary.red(), delta);
+            Assert.assertEquals("green", 0f, primary.green(), delta);
+            Assert.assertEquals("blue", 0f, primary.blue(), delta);
+
+            Assert.assertNull(colors.getSecondaryColor());
+            Assert.assertNull(colors.getTertiaryColor());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            tmpWallpaper.recycle();
+        }
+    }
+
+
+    @Test
+    public void wallpaperColors_secondary() {
+        Bitmap tmpWallpaper = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(tmpWallpaper);
+        canvas.drawColor(Color.RED);
+        // Make 20% of the wallpaper BLUE so that secondary color is BLUE
+        canvas.clipRect(0, 0, 100, 20);
+        canvas.drawColor(Color.BLUE);
+
+        try {
+            mWallpaperManager.setBitmap(tmpWallpaper);
+            WallpaperColors colors = mWallpaperManager.getWallpaperColors(
+                    WallpaperManager.FLAG_SYSTEM);
+
+            // Check that the secondary color is almost blue
+            Color secondary = colors.getSecondaryColor();
+            final float delta = 0.1f;
+            Assert.assertEquals("red", 0f, secondary.red(), delta);
+            Assert.assertEquals("green", 0f, secondary.green(), delta);
+            Assert.assertEquals("blue", 1f, secondary.blue(), delta);
+
+            Assert.assertNull(colors.getTertiaryColor());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            tmpWallpaper.recycle();
+        }
+    }
+
     private void assertDesiredDimension(Point suggestedSize, Point expectedSize) {
         mWallpaperManager.suggestDesiredDimensions(suggestedSize.x, suggestedSize.y);
         Point actualSize = new Point(mWallpaperManager.getDesiredMinimumWidth(),
diff --git a/tests/app/src/android/app/cts/WearableExtenderTest.java b/tests/app/src/android/app/cts/WearableExtenderTest.java
new file mode 100644
index 0000000..eb3e5d8
--- /dev/null
+++ b/tests/app/src/android/app/cts/WearableExtenderTest.java
@@ -0,0 +1,275 @@
+/*
+ * 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.app.cts;
+
+import android.app.Notification;
+import android.app.Notification.Action;
+import android.app.Notification.WearableExtender;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.view.Gravity;
+import java.util.ArrayList;
+import java.util.List;
+
+public class WearableExtenderTest extends AndroidTestCase {
+
+    private Context mContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getContext();
+    }
+
+    public void testWearableExtender() {
+        final String bridgeTag = "bridge_tag";
+        final String dismissalId = "dismissal_id";
+        final int contentActionIndex = 2;
+        final Bitmap background = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        Notification page1 = new Notification.Builder(mContext, "test id")
+            .setSmallIcon(1)
+            .setContentTitle("page1")
+            .build();
+        Notification page2 = new Notification.Builder(mContext, "test id")
+            .setSmallIcon(1)
+            .setContentTitle("page2")
+            .build();
+        List<Notification> pages = new ArrayList<>();
+        pages.add(page2);
+        final int gravity = Gravity.LEFT;
+        final int icon = 3;
+        final int height = 4;
+        final int size = 5;
+        final int timeout = 6;
+
+        WearableExtender extender = new WearableExtender()
+                .setStartScrollBottom(true)
+                .setContentIntentAvailableOffline(true)
+                .setHintContentIntentLaunchesActivity(true)
+                .setBridgeTag(bridgeTag)
+                .setDismissalId(dismissalId)
+                .setContentAction(contentActionIndex)
+                // deprecated methods follow
+                .setBackground(background)
+                .setGravity(gravity)
+                .setContentIcon(icon)
+                .setContentIconGravity(gravity)
+                .setCustomContentHeight(height)
+                .setCustomSizePreset(size)
+                .setDisplayIntent(pendingIntent)
+                .setHintAmbientBigPicture(true)
+                .setHintAvoidBackgroundClipping(true)
+                .setHintHideIcon(true)
+                .setHintScreenTimeout(timeout)
+                .setHintShowBackgroundOnly(true)
+                .addPage(page1)
+                .clearPages()
+                .addPages(pages);
+
+        assertTrue(extender.getStartScrollBottom());
+        assertTrue(extender.getContentIntentAvailableOffline());
+        assertTrue(extender.getHintContentIntentLaunchesActivity());
+        assertEquals(bridgeTag, extender.getBridgeTag());
+        assertEquals(dismissalId, extender.getDismissalId());
+        assertEquals(contentActionIndex, extender.getContentAction());
+        // deprecated methods follow
+        assertEquals(background, extender.getBackground());
+        assertEquals(gravity, extender.getGravity());
+        assertEquals(icon, extender.getContentIcon());
+        assertEquals(gravity, extender.getContentIconGravity());
+        assertEquals(height, extender.getCustomContentHeight());
+        assertEquals(size, extender.getCustomSizePreset());
+        assertEquals(pendingIntent, extender.getDisplayIntent());
+        assertTrue(extender.getHintAmbientBigPicture());
+        assertTrue(extender.getHintAvoidBackgroundClipping());
+        assertTrue(extender.getHintHideIcon());
+        assertEquals(timeout, extender.getHintScreenTimeout());
+        assertTrue(extender.getHintShowBackgroundOnly());
+        assertEquals(1, extender.getPages().size());
+        assertEquals(page2, extender.getPages().get(0));
+    }
+
+    public void testWearableExtenderActions() {
+        Notification.Action a = newActionBuilder().build();
+        Notification.Action b = newActionBuilder().build();
+        Notification.Action c = newActionBuilder().build();
+        List<Action> actions = new ArrayList<>();
+        actions.add(b);
+        actions.add(c);
+
+        WearableExtender extender = new WearableExtender()
+                .addAction(a)
+                .addActions(actions)
+                .setContentAction(1);
+
+        assertEquals(3, extender.getActions().size());
+        assertEquals(b, extender.getActions().get(extender.getContentAction()));
+    }
+
+    public void testWearableExtender_clearActions() {
+        WearableExtender extender = new WearableExtender()
+                .addAction(newActionBuilder().build());
+
+        extender.clearActions();
+
+        assertEquals(0, extender.getActions().size());
+    }
+
+    public void testWearableExtender_clone() {
+        final String bridgeTag = "bridge_tag";
+        final String dismissalId = "dismissal_id";
+        final int contentActionIndex = 2;
+        WearableExtender original = new WearableExtender()
+                .addAction(newActionBuilder().build())
+                .setStartScrollBottom(true)
+                .setContentIntentAvailableOffline(true)
+                .setHintContentIntentLaunchesActivity(true)
+                .setBridgeTag(bridgeTag)
+                .setDismissalId(dismissalId)
+                .setContentAction(contentActionIndex);
+
+        // WHEN the enter is cloned
+        WearableExtender clone = original.clone();
+        // and WHEN the original is modified
+        original.clearActions();
+
+        assertTrue(clone.getStartScrollBottom());
+        assertTrue(clone.getContentIntentAvailableOffline());
+        assertTrue(clone.getHintContentIntentLaunchesActivity());
+        assertEquals(bridgeTag, clone.getBridgeTag());
+        assertEquals(dismissalId, clone.getDismissalId());
+        assertEquals(contentActionIndex, clone.getContentAction());
+        assertEquals(1, clone.getActions().size());
+    }
+
+    public void testWearableExtender_extend() {
+        final String title = "test_title";
+        final String bridgeTag = "bridge_tag";
+        final String dismissalId = "dismissal_id";
+        final int contentActionIndex = 2;
+        Notification.Builder notifBuilder = new Notification.Builder(mContext, "test id")
+                .setSmallIcon(1)
+                .setContentTitle(title);
+        WearableExtender extender = new WearableExtender()
+                .addAction(newActionBuilder().build())
+                .setStartScrollBottom(true)
+                .setContentIntentAvailableOffline(true)
+                .setHintContentIntentLaunchesActivity(true)
+                .setBridgeTag(bridgeTag)
+                .setDismissalId(dismissalId)
+                .setContentAction(contentActionIndex);
+
+        extender.extend(notifBuilder);
+
+        WearableExtender result = new WearableExtender(notifBuilder.build());
+        assertTrue(result.getStartScrollBottom());
+        assertTrue(result.getContentIntentAvailableOffline());
+        assertTrue(result.getHintContentIntentLaunchesActivity());
+        assertEquals(bridgeTag, result.getBridgeTag());
+        assertEquals(dismissalId, result.getDismissalId());
+        assertEquals(contentActionIndex, result.getContentAction());
+        assertEquals(1, result.getActions().size());
+    }
+
+    public void testWriteToParcel() {
+        final String bridgeTag = "bridge_tag";
+        final String dismissalId = "dismissal_id";
+        final int contentActionIndex = 2;
+        Notification.Action action = newActionBuilder().build();
+        final Bitmap background = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        Notification page1 = new Notification.Builder(mContext, "test id")
+            .setSmallIcon(1)
+            .setContentTitle("page1")
+            .build();
+        Notification page2 = new Notification.Builder(mContext, "test id")
+            .setSmallIcon(1)
+            .setContentTitle("page2")
+            .build();
+        List<Notification> pages = new ArrayList<>();
+        pages.add(page2);
+        final int gravity = Gravity.LEFT;
+        final int icon = 3;
+        final int height = 4;
+        final int size = 5;
+        final int timeout = 6;
+
+        Notification notif = new Notification.Builder(mContext, "test id")
+                .setSmallIcon(1)
+                .setContentTitle("test_title")
+                .extend(new Notification.WearableExtender()
+                        .setStartScrollBottom(true)
+                        .setContentIntentAvailableOffline(true)
+                        .setHintContentIntentLaunchesActivity(true)
+                        .setBridgeTag(bridgeTag)
+                        .setDismissalId(dismissalId)
+                        .addAction(action)
+                        .setContentAction(contentActionIndex)
+                        // deprecated methods follow
+                        .setBackground(background)
+                        .setGravity(gravity)
+                        .setContentIcon(icon)
+                        .setContentIconGravity(gravity)
+                        .setCustomContentHeight(height)
+                        .setCustomSizePreset(size)
+                        .setDisplayIntent(pendingIntent)
+                        .setHintAmbientBigPicture(true)
+                        .setHintAvoidBackgroundClipping(true)
+                        .setHintHideIcon(true)
+                        .setHintScreenTimeout(timeout)
+                        .setHintShowBackgroundOnly(true)
+                        .addPage(page1))
+                .build();
+
+        Parcel parcel = Parcel.obtain();
+        notif.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        Notification result = new Notification(parcel);
+
+        WearableExtender extender = new WearableExtender(result);
+        assertTrue(extender.getStartScrollBottom());
+        assertTrue(extender.getContentIntentAvailableOffline());
+        assertTrue(extender.getHintContentIntentLaunchesActivity());
+        assertEquals(bridgeTag, extender.getBridgeTag());
+        assertEquals(dismissalId, extender.getDismissalId());
+        assertEquals(contentActionIndex, extender.getContentAction());
+        assertEquals(1, extender.getActions().size());
+        // deprecated methods follow
+        assertNotNull(extender.getBackground());
+        assertEquals(gravity, extender.getGravity());
+        assertEquals(icon, extender.getContentIcon());
+        assertEquals(gravity, extender.getContentIconGravity());
+        assertEquals(height, extender.getCustomContentHeight());
+        assertEquals(size, extender.getCustomSizePreset());
+        assertEquals(pendingIntent, extender.getDisplayIntent());
+        assertTrue(extender.getHintAmbientBigPicture());
+        assertTrue(extender.getHintAvoidBackgroundClipping());
+        assertTrue(extender.getHintHideIcon());
+        assertEquals(timeout, extender.getHintScreenTimeout());
+        assertTrue(extender.getHintShowBackgroundOnly());
+        assertEquals(1, extender.getPages().size());
+    }
+
+    private static Notification.Action.Builder newActionBuilder() {
+        return new Notification.Action.Builder(0, "title", null);
+    }
+}
\ No newline at end of file
diff --git a/tests/autofillservice/Android.mk b/tests/autofillservice/Android.mk
index 5d74e87..3b8ff6c 100644
--- a/tests/autofillservice/Android.mk
+++ b/tests/autofillservice/Android.mk
@@ -29,6 +29,7 @@
     ctstestrunner \
     truth-prebuilt \
     ub-uiautomator \
+    CtsMockInputMethodLib \
     testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 5955274..eee73f5 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -27,7 +27,8 @@
 
         <uses-library android:name="android.test.runner" />
 
-        <activity android:name=".LoginActivity" >
+        <activity android:name=".LoginActivity"
+                  android:screenOrientation="portrait">
             <intent-filter>
                 <!-- This intent filter is not really needed by CTS, but it makes easier to launch
                      this app during CTS development... -->
diff --git a/tests/autofillservice/AndroidTest.xml b/tests/autofillservice/AndroidTest.xml
index e7413b1..d59e349 100644
--- a/tests/autofillservice/AndroidTest.xml
+++ b/tests/autofillservice/AndroidTest.xml
@@ -24,6 +24,16 @@
     <option name="test-file-name" value="CtsAutoFillServiceTestCases.apk" />
   </target_preparer>
 
+  <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+    <option name="cleanup-apks" value="true" />
+      <!--
+          MockIME always needs to be installed as a full package, even when CTS is running
+          for instant apps.
+      -->
+    <option name="force-install-mode" value="FULL"/>
+    <option name="test-file-name" value="CtsMockInputMethod.apk" />
+  </target_preparer>
+
   <!--  TODO: preparer below should be enabled only when running as cts-instant -->
   <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
     <option name="run-command" value="cmd autofill set bind-instant-service-allowed true" />
@@ -36,4 +46,10 @@
     <option name="shell-timeout" value="12000000"/>
   </test>
 
+  <!-- Collect the files generated on error -->
+  <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+    <option name="directory-keys" value="/sdcard/CtsAutoFillServiceTestCases" />
+    <option name="collect-on-run-ended-only" value="true" />
+    <option name="clean-up" value="false" />
+  </metrics_collector>
 </configuration>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
index cb98b54..92821a3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
@@ -53,7 +53,7 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
     public void testDatasetAuthTwoFieldsUserCancelsFirstAttempt() throws Exception {
         datasetAuthTwoFields(true);
     }
@@ -136,7 +136,7 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
     public void testDatasetAuthTwoFieldsReplaceResponse() throws Exception {
         // Set service.
         enableService();
@@ -198,7 +198,7 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
     public void testDatasetAuthTwoFieldsNoValues() throws Exception {
         // Set service.
         enableService();
@@ -242,7 +242,7 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
     public void testDatasetAuthTwoDatasets() throws Exception {
         // Set service.
         enableService();
@@ -297,13 +297,13 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
     public void testDatasetAuthMixedSelectAuth() throws Exception {
         datasetAuthMixedTest(true);
     }
 
     @Test
-    @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
     public void testDatasetAuthMixedSelectNonAuth() throws Exception {
         datasetAuthMixedTest(false);
     }
@@ -363,7 +363,7 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
     public void testDatasetAuthNoFiltering() throws Exception {
         // Set service.
         enableService();
@@ -421,7 +421,7 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
     public void testDatasetAuthFilteringUsingAutofillValue() throws Exception {
         // Set service.
         enableService();
@@ -577,13 +577,13 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
     public void testDatasetAuthMixedFilteringSelectAuth() throws Exception {
         datasetAuthMixedFilteringTest(true);
     }
 
     @Test
-    @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
     public void testDatasetAuthMixedFilteringSelectNonAuth() throws Exception {
         datasetAuthMixedFilteringTest(false);
     }
@@ -668,13 +668,13 @@
     }
 
     @Test
-    @AppModeFull // testDatasetAuthClientStateSetOnIntentOnly() is enough to test ephemeral apps
+    @AppModeFull(reason = "testDatasetAuthClientStateSetOnIntentOnly() is enough")
     public void testDatasetAuthClientStateSetOnFillResponseOnly() throws Exception {
         fillDatasetAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
     }
 
     @Test
-    @AppModeFull // testDatasetAuthClientStateSetOnIntentOnly() is enough to test ephemeral apps
+    @AppModeFull(reason = "testDatasetAuthClientStateSetOnIntentOnly() is enough")
     public void testDatasetAuthClientStateSetOnIntentAndFillResponse() throws Exception {
         fillDatasetAuthWithClientState(ClientStateLocation.BOTH);
     }
@@ -743,7 +743,7 @@
     }
 
     @Test
-    @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
     public void testFillResponseAuthBothFieldsUserCancelsFirstAttempt() throws Exception {
         fillResponseAuthBothFields(true);
     }
@@ -837,7 +837,7 @@
     }
 
     @Test
-    @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
     public void testFillResponseAuthJustOneField() throws Exception {
         // Set service.
         enableService();
@@ -902,7 +902,7 @@
     }
 
     @Test
-    @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
     public void testFillResponseAuthWhenAppCallsCancel() throws Exception {
         // Set service.
         enableService();
@@ -955,13 +955,13 @@
     }
 
     @Test
-    @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
     public void testFillResponseAuthServiceHasNoDataButCanSave() throws Exception {
         fillResponseAuthServiceHasNoDataTest(true);
     }
 
     @Test
-    @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
     public void testFillResponseAuthServiceHasNoData() throws Exception {
         fillResponseAuthServiceHasNoDataTest(false);
     }
@@ -1034,13 +1034,13 @@
     }
 
     @Test
-    @AppModeFull // testFillResponseAuthClientStateSetOnIntentOnly() is enough to test ephemeral
+    @AppModeFull(reason = "testFillResponseAuthClientStateSetOnIntentOnly() is enough")
     public void testFillResponseAuthClientStateSetOnFillResponseOnly() throws Exception {
         fillResponseAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
     }
 
     @Test
-    @AppModeFull // testFillResponseAuthClientStateSetOnIntentOnly() is enough to test ephemeral
+    @AppModeFull(reason = "testFillResponseAuthClientStateSetOnIntentOnly() is enough")
     public void testFillResponseAuthClientStateSetOnIntentAndFillResponse() throws Exception {
         fillResponseAuthWithClientState(ClientStateLocation.BOTH);
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index be2625e..40d1e4e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -202,6 +202,11 @@
                 // mRetryRule should be closest to the main test as possible
                 .around(mRetryRule)
                 //
+                // TODO(b/124006095): must use DeviceConfig rule
+//                // Augmented Autofill should be disabled by default
+//                .around(new SettingsStateChangerRule(sContext, SettingsUtils.NAMESPACE_GLOBAL,
+//                        AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
+//                        Integer.toString(getSmartSuggestionMode())))
                 //
                 // Finally, let subclasses add their own rules (like ActivityTestRule)
                 .around(getMainTestRule());
@@ -217,6 +222,10 @@
             mUiBot.reset();
         }
 
+        protected int getSmartSuggestionMode() {
+            return 0;
+        }
+
         /**
          * Gets how many times a test should be retried.
          *
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
index 3a0c294..cabdee3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
@@ -51,7 +51,7 @@
  *  redundant tests and add more tests (like triggering autofill using different views) to
  *  CheckoutActivityTest.
  */
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class AutofillValueTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<AllAutofillableViewsActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java b/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java
index 805db4e..73817f6 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java
@@ -32,7 +32,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class BatchUpdatesTest {
 
     private final BatchUpdates.Builder mBuilder = new BatchUpdates.Builder();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
index 004928a..646aa61 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
@@ -38,7 +38,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class CharSequenceTransformationTest {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index ac181ec..dead535 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -115,7 +115,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofill() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofill() is enough")
     public void testAutofillDynamicAdapter() throws Exception {
         // Set activity.
         mActivity.onCcExpiration((v) -> v.setAdapter(new ArrayAdapter<String>(getContext(),
@@ -158,7 +158,7 @@
     // TODO: this should be a pure unit test exercising onProvideAutofillStructure(),
     // but that would require creating a custom ViewStructure.
     @Test
-    @AppModeFull // Unit test
+    @AppModeFull(reason = "Unit test")
     public void testGetAutofillOptionsSorted() throws Exception {
         // Set service.
         enableService();
@@ -248,13 +248,13 @@
     }
 
     @Test
-    @AppModeFull // Service-specific test
+    @AppModeFull(reason = "Service-specific test")
     public void testCustomizedSaveUi() throws Exception {
         customizedSaveUi(false);
     }
 
     @Test
-    @AppModeFull // Service-specific test
+    @AppModeFull(reason = "Service-specific test")
     public void testCustomizedSaveUiWithContentDescription() throws Exception {
         customizedSaveUi(true);
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java b/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java
index bb429d4..a00e0d3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java
@@ -33,7 +33,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class CompositeUserDataTest {
 
     private final String mShortValue = Strings.repeat("k", UserData.getMinValueLength() - 1);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java
index 49e772d..13896aa 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java
@@ -37,7 +37,7 @@
 
 import java.util.Calendar;
 
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class CustomDescriptionDateTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<DatePickerSpinnerActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
index 2f48835..2abde4f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
@@ -46,7 +46,7 @@
 import java.util.function.BiFunction;
 import java.util.regex.Pattern;
 
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class CustomDescriptionTest extends AbstractLoginActivityTestCase {
 
     /**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java
index 39f3a58..5b3f62d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java
@@ -38,7 +38,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class CustomDescriptionUnitTest {
 
     private final CustomDescription.Builder mBuilder =
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
index 85e07ba..9a2138a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
@@ -17,14 +17,27 @@
 package android.autofillservice.cts;
 
 import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
 
 import static com.android.compatibility.common.util.ShellUtils.sendKeyEvent;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
 
 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
 import android.content.IntentSender;
+import android.os.Process;
 import android.platform.test.annotations.AppModeFull;
+import android.support.test.InstrumentationRegistry;
+import android.view.View;
 import android.widget.EditText;
 
+import com.android.cts.mockime.ImeCommand;
+import com.android.cts.mockime.ImeEventStream;
+import com.android.cts.mockime.ImeSettings;
+import com.android.cts.mockime.MockImeSession;
+
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -103,7 +116,7 @@
     }
 
     @Test
-    public void testFilter_usingKeyboard() throws Exception {
+    public void testFilter_injectingEvents() throws Exception {
         final String aa = "Two A's";
         final String ab = "A and B";
         final String b = "Only B";
@@ -159,7 +172,78 @@
     }
 
     @Test
-    @AppModeFull // testFilter() is enough to test ephemeral apps support
+    public void testFilter_usingKeyboard() throws Exception {
+        final String aa = "Two A's";
+        final String ab = "A and B";
+        final String b = "Only B";
+
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "aa")
+                        .setPresentation(createPresentation(aa))
+                        .build())
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "ab")
+                        .setPresentation(createPresentation(ab))
+                        .build())
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "b")
+                        .setPresentation(createPresentation(b))
+                        .build())
+                .build());
+
+        final String marker = mActivity.getMarker();
+
+        try (MockImeSession mockImeSession = MockImeSession.create(
+                mContext, InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+                new ImeSettings.Builder())) {
+            final ImeEventStream stream = mockImeSession.openEventStream();
+
+            // Trigger auto-fill.
+            mActivity.onUsername(View::requestFocus);
+
+            // Wait until the MockIme gets bound to the TestActivity.
+            expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
+            expectEvent(stream, editorMatcher("onStartInput", marker), MOCK_IME_TIMEOUT_MS);
+
+            sReplier.getNextFillRequest();
+
+            // With no filter text all datasets should be shown
+            mUiBot.assertDatasets(aa, ab, b);
+
+            // Only two datasets start with 'a'
+            final ImeCommand cmd1 = mockImeSession.callCommitText("a", 1);
+            expectCommand(stream, cmd1, MOCK_IME_TIMEOUT_MS);
+
+            mUiBot.assertDatasets(aa, ab);
+
+            // Only one dataset start with 'aa'
+            final ImeCommand cmd2 = mockImeSession.callCommitText("a", 1);
+            expectCommand(stream, cmd2, MOCK_IME_TIMEOUT_MS);
+
+            mUiBot.assertDatasets(aa);
+
+            // Only two datasets start with 'a'
+            sendKeyEvent("KEYCODE_DEL"); // TODO: add new method on MockIme for it
+            mUiBot.assertDatasets(aa, ab);
+            // With no filter text all datasets should be shown
+            sendKeyEvent("KEYCODE_DEL"); // TODO: add new method on MockIme for it
+            mUiBot.assertDatasets(aa, ab, b);
+
+            // No dataset start with 'aaa'
+            final MyAutofillCallback callback = mActivity.registerCallback();
+            final ImeCommand cmd3 = mockImeSession.callCommitText("aaa", 1);
+            expectCommand(stream, cmd3, MOCK_IME_TIMEOUT_MS);
+            callback.assertUiHiddenEvent(mActivity.getUsername());
+            mUiBot.assertNoDatasets();
+        }
+    }
+
+    @Test
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_nullValuesAlwaysMatched() throws Exception {
         final String aa = "Two A's";
         final String ab = "A and B";
@@ -212,7 +296,7 @@
     }
 
     @Test
-    @AppModeFull // testFilter() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_differentPrefixes() throws Exception {
         final String a = "aaa";
         final String b = "bra";
@@ -254,7 +338,7 @@
     }
 
     @Test
-    @AppModeFull // testFilter() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_usingRegex() throws Exception {
         // Dataset presentations.
         final String aa = "Two A's";
@@ -310,7 +394,7 @@
     }
 
     @Test
-    @AppModeFull // testFilter() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_disabledUsingNullRegex() throws Exception {
         // Dataset presentations.
         final String unfilterable = "Unfilterabled";
@@ -373,7 +457,7 @@
     }
 
     @Test
-    @AppModeFull // testFilter() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_mixPlainAndRegex() throws Exception {
         final String plain = "Plain";
         final String regexPlain = "RegexPlain";
@@ -425,7 +509,7 @@
     }
 
     @Test
-    @AppModeFull // testFilter_usingKeyboard() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testFilter_usingKeyboard() is enough")
     public void testFilter_mixPlainAndRegex_usingKeyboard() throws Exception {
         final String plain = "Plain";
         final String regexPlain = "RegexPlain";
@@ -477,16 +561,19 @@
     }
 
     @Test
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_resetFilter_chooseFirst() throws Exception {
         resetFilterTest(1);
     }
 
     @Test
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_resetFilter_chooseSecond() throws Exception {
         resetFilterTest(2);
     }
 
     @Test
+    @AppModeFull(reason = "testFilter() is enough")
     public void testFilter_resetFilter_chooseThird() throws Exception {
         resetFilterTest(3);
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
index 2554a5b..5202f52 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
@@ -34,7 +34,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class DatasetTest {
 
     private final AutofillId mId = new AutofillId(42);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
index 35f3b73..decc4b7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AppModeFull;
 
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class DatePickerCalendarActivityTest extends DatePickerTestCase<DatePickerCalendarActivity> {
 
     @Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
index 291d5aa..4b63e10 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AppModeFull;
 
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class DatePickerSpinnerActivityTest extends DatePickerTestCase<DatePickerSpinnerActivity> {
 
     @Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java
index 8f2d0ee..c6385ed 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java
@@ -39,7 +39,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class DateTransformationTest {
 
     @Mock private ValueFinder mValueFinder;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java b/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java
index 6f59302..f30aaf0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java
@@ -34,7 +34,7 @@
 import java.util.Date;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class DateValueSanitizerTest {
 
     private static final String TAG = "DateValueSanitizerTest";
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java b/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
index 77f5efd..49a43fe 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
@@ -207,7 +207,7 @@
     }
 
     @Test
-    @AppModeFull // testDisableApp() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDisableApp() is enough")
     public void testDisableAppThenWaitToReenableIt() throws Exception {
         // Set service.
         enableService();
@@ -233,7 +233,7 @@
     }
 
     @Test
-    @AppModeFull // testDisableApp() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDisableApp() is enough")
     public void testDisableAppThenResetServiceToReenableIt() throws Exception {
         enableService();
         sReplier.addResponse(new CannedFillResponse.Builder()
@@ -277,7 +277,7 @@
     }
 
     @Test
-    @AppModeFull // testDisableActivity() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDisableActivity() is enough")
     public void testDisableActivityThenWaitToReenableIt() throws Exception {
         // Set service.
         enableService();
@@ -306,7 +306,7 @@
     }
 
     @Test
-    @AppModeFull // testDisableActivity() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testDisableActivity() is enough")
     public void testDisableActivityThenResetServiceToReenableIt() throws Exception {
         enableService();
         sReplier.addResponse(new CannedFillResponse.Builder()
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
index 5f81df2..20a184f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
@@ -44,7 +44,7 @@
 
 import java.util.List;
 
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class FieldsClassificationTest extends AbstractGridActivityTestCase {
 
     @ClassRule
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java b/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java
index 2e1ae0d..2c6bfe5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java
@@ -63,7 +63,7 @@
 /**
  * Test that uses {@link LoginActivity} to test {@link FillEventHistory}.
  */
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class FillEventHistoryTest extends AbstractLoginActivityTestCase {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java b/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
index f0b7bad..adae5f7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
@@ -40,7 +40,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class FillResponseTest {
 
     private final AutofillId mAutofillId = new AutofillId(42);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
index f0f5470..317c3fa 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
@@ -37,7 +37,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class ImageTransformationTest {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
index 974f0cc..43000cc 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
@@ -35,7 +35,7 @@
 /**
  * Test case for an activity containing non-TextField views with initial values set on XML.
  */
-@AppModeFull // CheckoutActivityTest() is enough to test ephemeral apps support
+@AppModeFull(reason = "CheckoutActivityTest() is enough")
 public class InitializedCheckoutActivityTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<InitializedCheckoutActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
index 939792c..4cebbb2 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -55,6 +56,8 @@
     public static final String BACKDOOR_USERNAME = "LemmeIn";
     public static final String BACKDOOR_PASSWORD_SUBSTRING = "pass";
 
+    private static final String TEST_MARKER_PREFIX = "android.autofillservice.cts.LoginActivity";
+
     private LinearLayout mUsernameContainer;
     private TextView mUsernameLabel;
     private EditText mUsernameEditText;
@@ -71,6 +74,9 @@
     private CountDownLatch mLoginLatch;
     private String mLoginMessage;
 
+    private final String mTestMarker = TEST_MARKER_PREFIX + "/"
+            + SystemClock.elapsedRealtimeNanos();
+
     /**
      * Gets the expected welcome message for a given username.
      */
@@ -78,6 +84,13 @@
         return String.format(WELCOME_TEMPLATE,  username);
     }
 
+    /**
+     * Gets the marker used on MockIME-based tests.
+     */
+    String getMarker() {
+        return mTestMarker;
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -90,6 +103,8 @@
         mCancelButton = findViewById(R.id.cancel);
         mUsernameLabel = findViewById(R.id.username_label);
         mUsernameEditText = findViewById(R.id.username);
+        Log.d(TAG, "marker: " + mTestMarker);
+        mUsernameEditText.setPrivateImeOptions(mTestMarker);
         mPasswordLabel = findViewById(R.id.password_label);
         mPasswordEditText = findViewById(R.id.password);
         mOutput = findViewById(R.id.output);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index e39cdf9..d5325f7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -134,13 +134,13 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutofillManuallyAfterServiceReturnedNoDatasets() throws Exception {
         autofillAfterServiceReturnedNoDatasets(true);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutofillAutomaticallyAfterServiceReturnedNoDatasets() throws Exception {
         autofillAfterServiceReturnedNoDatasets(false);
     }
@@ -187,13 +187,13 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutofillManuallyAndSaveAfterServiceReturnedNoDatasets() throws Exception {
         autofillAndSaveAfterServiceReturnedNoDatasets(true);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutofillAutomaticallyAndSaveAfterServiceReturnedNoDatasets() throws Exception {
         autofillAndSaveAfterServiceReturnedNoDatasets(false);
     }
@@ -227,7 +227,7 @@
      * workflow was requested.
      */
     @Test
-    @AppModeFull // testAutoFillNoDatasets() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillNoDatasets() is enough")
     public void testMultipleIterationsAfterServiceReturnedNoDatasets() throws Exception {
         // Set service.
         enableService();
@@ -270,7 +270,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyAlwaysCallServiceAgain() throws Exception {
         // Set service.
         enableService();
@@ -304,13 +304,13 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset_withHeaderAndFooter() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset_withHeaderAndFooter() is enough")
     public void testAutoFillOneDataset_withHeader() throws Exception {
         autofillOneDatasetTest(BorderType.HEADER_ONLY);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset_withHeaderAndFooter() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset_withHeaderAndFooter() is enough")
     public void testAutoFillOneDataset_withFooter() throws Exception {
         autofillOneDatasetTest(BorderType.FOOTER_ONLY);
     }
@@ -382,6 +382,7 @@
 
 
     @Test
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutofillAgainAfterOnFailure() throws Exception {
         // Set service.
         enableService();
@@ -416,9 +417,10 @@
 
     @Test
     public void testDatasetPickerPosition() throws Exception {
-        // TODO: currently disabled because the screenshot contains elements external to the
-        // activity that can change (for exmaple, clock), which causes flakiness to the test.
+        // TODO(b/75281985): currently disabled because the screenshot contains elements external to
+        // the activity that can change (for exmaple, clock), which causes flakiness to the test.
         final boolean compareBitmaps = false;
+
         final boolean pickerAndViewBoundsMatches = !isAutofillWindowFullScreen(mContext);
 
         // Set service.
@@ -500,7 +502,7 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutoFillTwoDatasetsSameNumberOfFields() throws Exception {
         // Set service.
         enableService();
@@ -539,13 +541,13 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsAll() throws Exception {
         autoFillTwoDatasetsUnevenNumberOfFieldsTest(true);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsOne() throws Exception {
         autoFillTwoDatasetsUnevenNumberOfFieldsTest(false);
     }
@@ -597,7 +599,7 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutoFillDatasetWithoutFieldIsIgnored() throws Exception {
         // Set service.
         enableService();
@@ -791,7 +793,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutofillCallbacks() is enough")
     public void testAutofillCallbackDisabled() throws Exception {
         // Set service.
         disableService();
@@ -807,13 +809,13 @@
     }
 
     @Test
-    @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutofillCallbacks() is enough")
     public void testAutofillCallbackNoDatasets() throws Exception {
         callbackUnavailableTest(NO_RESPONSE);
     }
 
     @Test
-    @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutofillCallbacks() is enough")
     public void testAutofillCallbackNoDatasetsButSaveInfo() throws Exception {
         callbackUnavailableTest(new CannedFillResponse.Builder()
                 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
@@ -1030,19 +1032,19 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutoFillMultipleDatasetsPickFirst() throws Exception {
         multipleDatasetsTest(1);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutoFillMultipleDatasetsPickSecond() throws Exception {
         multipleDatasetsTest(2);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutoFillMultipleDatasetsPickThird() throws Exception {
         multipleDatasetsTest(3);
     }
@@ -1146,7 +1148,7 @@
      * and password) and the dataset itself, and each dataset has the same number of fields.
      */
     @Test
-    @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
     public void testAutofillMultipleDatasetsCustomPresentations() throws Exception {
         // Set service.
         enableService();
@@ -1191,7 +1193,7 @@
      * and password), and each dataset has the same number of fields.
      */
     @Test
-    @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
     public void testAutofillMultipleDatasetsCustomPresentationSameFields() throws Exception {
         // Set service.
         enableService();
@@ -1235,7 +1237,7 @@
      * and password), but each dataset has a different number of fields.
      */
     @Test
-    @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
     public void testAutofillMultipleDatasetsCustomPresentationFirstDatasetMissingSecondField()
             throws Exception {
         // Set service.
@@ -1278,7 +1280,7 @@
      * and password), but each dataset has a different number of fields.
      */
     @Test
-    @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
     public void testAutofillMultipleDatasetsCustomPresentationSecondDatasetMissingFirstField()
             throws Exception {
         // Set service.
@@ -1317,13 +1319,13 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveOnly() throws Exception {
         saveOnlyTest(false);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveOnlyTriggeredManually() throws Exception {
         saveOnlyTest(false);
     }
@@ -1441,13 +1443,13 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveOnlyPreFilled() throws Exception {
         saveOnlyTestPreFilled(false);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveOnlyTriggeredManuallyPreFilled() throws Exception {
         saveOnlyTestPreFilled(true);
     }
@@ -1506,7 +1508,7 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveOnlyTwoRequiredFieldsOnePrefilled() throws Exception {
         enableService();
 
@@ -1553,7 +1555,7 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveOnlyOptionalField() throws Exception {
         enableService();
 
@@ -1596,19 +1598,19 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveNoRequiredField_NoneFilled() throws Exception {
         optionalOnlyTest(FilledFields.NONE);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveNoRequiredField_OneFilled() throws Exception {
         optionalOnlyTest(FilledFields.USERNAME_ONLY);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSaveNoRequiredField_BothFilled() throws Exception {
         optionalOnlyTest(FilledFields.BOTH);
     }
@@ -1677,37 +1679,37 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testGenericSave() throws Exception {
         customizedSaveTest(SAVE_DATA_TYPE_GENERIC);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testCustomizedSavePassword() throws Exception {
         customizedSaveTest(SAVE_DATA_TYPE_PASSWORD);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testCustomizedSaveAddress() throws Exception {
         customizedSaveTest(SAVE_DATA_TYPE_ADDRESS);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testCustomizedSaveCreditCard() throws Exception {
         customizedSaveTest(SAVE_DATA_TYPE_CREDIT_CARD);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testCustomizedSaveUsername() throws Exception {
         customizedSaveTest(SAVE_DATA_TYPE_USERNAME);
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testCustomizedSaveEmailAddress() throws Exception {
         customizedSaveTest(SAVE_DATA_TYPE_EMAIL_ADDRESS);
     }
@@ -1796,7 +1798,7 @@
     }
 
     @Test
-    @AppModeFull // Service-specific test
+    @AppModeFull(reason = "Service-specific test")
     public void testDisableSelf() throws Exception {
         enableService();
 
@@ -1903,7 +1905,7 @@
     }
 
     @Test
-    @AppModeFull // Unit test
+    @AppModeFull(reason = "Unit test")
     public void testGetTextInputType() throws Exception {
         // Set service.
         enableService();
@@ -1926,7 +1928,7 @@
     }
 
     @Test
-    @AppModeFull // Unit test
+    @AppModeFull(reason = "Unit test")
     public void testNoContainers() throws Exception {
         // Set service.
         enableService();
@@ -1994,6 +1996,7 @@
     }
 
     @Test
+    @AppModeFull(reason = "testAutoFillOneDataset() is enough")
     public void testAutofillManuallyOneDatasetWhenClipboardFull() throws Exception {
         // Set service.
         enableService();
@@ -2030,13 +2033,13 @@
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
         autofillManuallyTwoDatasets(true);
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
         autofillManuallyTwoDatasets(false);
     }
@@ -2080,7 +2083,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyPartialField() throws Exception {
         // Set service.
         enableService();
@@ -2115,7 +2118,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyAgainAfterAutomaticallyAutofilledBefore() throws Exception {
         // Set service.
         enableService();
@@ -2176,7 +2179,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyAgainAfterManuallyAutofilledBefore() throws Exception {
         // Set service.
         enableService();
@@ -2449,13 +2452,13 @@
 
     // TODO(b/70682223): add a new test to make sure service with BIND_AUTOFILL permission works
     @Test
-    @AppModeFull // Service-specific test
+    @AppModeFull(reason = "Service-specific test")
     public void testServiceIsDisabledWhenNewServiceInfoIsInvalid() throws Exception {
         serviceIsDisabledWhenNewServiceIsInvalid(BadAutofillService.SERVICE_NAME);
     }
 
     @Test
-    @AppModeFull // Service-specific test
+    @AppModeFull(reason = "Service-specific test")
     public void testServiceIsDisabledWhenNewServiceNameIsInvalid() throws Exception {
         serviceIsDisabledWhenNewServiceIsInvalid("Y_U_NO_VALID");
     }
@@ -2587,7 +2590,7 @@
     }
 
     @Test
-    @AppModeFull // Unit test
+    @AppModeFull(reason = "Unit test")
     public void testNewTextAttributes() throws Exception {
         enableService();
         sReplier.addResponse(NO_RESPONSE);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java
index bc8ed9f..e612161 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java
@@ -42,7 +42,7 @@
 
 import org.junit.Test;
 
-@AppModeFull // LoginActivityTest is enough to test ephemeral apps support
+@AppModeFull(reason = "LoginActivityTest is enough")
 public class LoginWithStringsActivityTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<LoginWithStringsActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
index 0da2208..590f1b9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
@@ -32,7 +32,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class LuhnChecksumValidatorTest {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
index 3d042f1..eaf60ba 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
@@ -33,6 +33,7 @@
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
 import android.content.ComponentName;
 import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
 import android.service.autofill.CharSequenceTransformation;
 import android.service.autofill.SaveInfo;
 import android.support.test.uiautomator.UiObject2;
@@ -47,6 +48,7 @@
 /**
  * Test case for the senario where a login screen is split in multiple activities.
  */
+@AppModeFull(reason = "Service-specific test")
 public class MultiScreenLoginTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<UsernameOnlyActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java
index d8b263a..885376a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java
@@ -41,7 +41,7 @@
 
 import java.util.concurrent.TimeoutException;
 
-@AppModeFull // This test requires android.permission.MANAGE_ACTIVITY_STACKS
+@AppModeFull(reason = "This test requires android.permission.MANAGE_ACTIVITY_STACKS")
 public class MultiWindowLoginActivityTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<MultiWindowLoginActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java b/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java
index a7918c9..0ebd0a4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java
@@ -46,7 +46,7 @@
 /**
  * Integration tests for the {@link OnClickAction} implementations.
  */
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class OnClickActionTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<SimpleSaveActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
index fe49410..c9cec8b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
@@ -46,7 +46,7 @@
  *   <li>Favorite Color: don't care - LOL
  * </ul>
  */
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class OptionalSaveActivityTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<OptionalSaveActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index 767c56d..6fd973e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -55,7 +55,7 @@
 /**
  * Test case for an activity containing multiple partitions.
  */
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class PartitionedActivityTest extends AbstractGridActivityTestCase {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
index c476722..fd392d5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
@@ -35,7 +35,7 @@
 /**
  * Covers scenarios where the behavior is different because some fields were pre-filled.
  */
-@AppModeFull // LoginActivityTest is enough to test ephemeral apps support
+@AppModeFull(reason = "LoginActivityTest is enough")
 public class PreFilledLoginActivityTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<PreFilledLoginActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java
index f0e68a6..cc26ec5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java
@@ -34,7 +34,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class RegexValidatorTest {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java b/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
index 1c009e9..4812574 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
@@ -36,7 +36,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class SaveInfoTest {
 
     private final AutofillId mId = new AutofillId(42);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java b/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java
index a27a5bd..2d5c722 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java
@@ -22,6 +22,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 import android.view.autofill.AutofillManager;
 
@@ -31,6 +32,7 @@
 /**
  * Test case that guarantee the service is disabled before the activity launches.
  */
+@AppModeFull(reason = "Service-specific test")
 public class ServiceDisabledForSureTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<OnCreateServiceStatusVerifierActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index b9bd41a..d93e3bd 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -62,7 +62,7 @@
 /**
  * Test the lifecycle of a autofill session
  */
-@AppModeFull // This test requires android.permission.WRITE_EXTERNAL_STORAGE
+@AppModeFull(reason = "This test requires android.permission.WRITE_EXTERNAL_STORAGE")
 public class SessionLifecycleTest extends AutoFillServiceTestCase.ManualActivityLaunch {
     private static final String TAG = "SessionLifecycleTest";
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java b/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
index 1ab9069..22ba3b9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
@@ -29,7 +29,7 @@
 import org.junit.After;
 import org.junit.Test;
 
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class SettingsIntentTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<TrampolineForResultActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
index 93ff57b..cec472e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
@@ -137,6 +137,7 @@
     }
 
     @Test
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testAutoFillOneDatasetAndSave_largeAssistStructure() throws Exception {
         startActivity();
 
@@ -249,7 +250,7 @@
     }
 
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testSave() throws Exception {
         saveTest(false);
     }
@@ -312,7 +313,7 @@
      * Emulates an app dyanmically adding the password field after username is typed.
      */
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testPartitionedSave() throws Exception {
         startActivity();
 
@@ -369,7 +370,7 @@
      * Emulates an app using fragments to display username and password in 2 steps.
      */
     @Test
-    @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
     public void testDelayedSave() throws Exception {
         startActivity();
 
@@ -941,7 +942,7 @@
     }
 
     @Test
-    @AppModeFull // Service-specific test
+    @AppModeFull(reason = "Service-specific test")
     public void testSelectedDatasetsAreSentOnSaveRequest() throws Exception {
         startActivity();
 
@@ -1098,7 +1099,7 @@
     }
 
     @Test
-    @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
     public void testSanitizeOnSaveNoChange() throws Exception {
         startActivity();
 
@@ -1136,7 +1137,7 @@
     }
 
     @Test
-    @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
     public void testDontSaveWhenSanitizedValueForRequiredFieldDidntChange() throws Exception {
         startActivity();
 
@@ -1174,7 +1175,7 @@
     }
 
     @Test
-    @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
     public void testDontSaveWhenSanitizedValueForOptionalFieldDidntChange() throws Exception {
         startActivity();
 
@@ -1208,7 +1209,7 @@
     }
 
     @Test
-    @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
     public void testDontSaveWhenRequiredFieldFailedSanitization() throws Exception {
         startActivity();
 
@@ -1243,7 +1244,7 @@
     }
 
     @Test
-    @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
     public void testDontSaveWhenOptionalFieldFailedSanitization() throws Exception {
         startActivity();
 
@@ -1279,7 +1280,7 @@
     }
 
     @Test
-    @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
     public void testDontSaveWhenInitialValueAndNoUserInputAndServiceDatasets() throws Throwable {
         // Prepare activitiy.
         startActivity();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java b/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java
index 2b6d5c6..1c9c246 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java
@@ -31,7 +31,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class TextValueSanitizerTest {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
index c7f3480..f07d994 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
@@ -17,7 +17,7 @@
 
 import android.platform.test.annotations.AppModeFull;
 
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class TimePickerClockActivityTest extends TimePickerTestCase<TimePickerClockActivity> {
 
     @Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
index a6ac44f..9245387 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
@@ -17,7 +17,7 @@
 
 import android.platform.test.annotations.AppModeFull;
 
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class TimePickerSpinnerActivityTest extends TimePickerTestCase<TimePickerSpinnerActivity> {
 
     @Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
index b65b91b..44027ef 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
@@ -26,6 +26,8 @@
     private static final long ONE_TIMEOUT_TO_RULE_THEN_ALL_MS = 20_000;
     private static final long ONE_NAPTIME_TO_RULE_THEN_ALL_MS = 2_000;
 
+    static final long MOCK_IME_TIMEOUT_MS = 5_000;
+
     /**
      * Timeout until framework binds / unbinds from service.
      */
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
index e0c2894..d0a675a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
@@ -42,7 +42,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class UserDataTest {
 
     private static final Context sContext = InstrumentationRegistry.getContext();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
index 85c6737..522fd98 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
@@ -37,7 +37,7 @@
 /**
  * Simple integration test to verify that the UI is only shown if the validator passes.
  */
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
 public class ValidatorTest extends AbstractLoginActivityTestCase {
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java b/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java
index bb4561b..63e2e3c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java
@@ -38,7 +38,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class ValidatorsTest {
 
     @Mock private Validator mInvalidValidator;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
index 8c88928..5b9c646 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
@@ -37,7 +37,7 @@
 import java.util.function.Consumer;
 
 @RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
 public class ViewAttributesTest
         extends AutoFillServiceTestCase.AutoActivityLaunch<ViewAttributesTestActivity> {
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
index 72688f6..af21337 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
@@ -121,7 +121,7 @@
     }
 
     @Test
-    @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
     public void testMultipleUrlBars_bothExist() throws Exception {
         SettingsUtils.syncSet(sContext, NAMESPACE_GLOBAL, AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
                 SERVICE_PACKAGE + "[my_url_bar,my_url_bar2]");
@@ -148,7 +148,7 @@
     }
 
     @Test
-    @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
     public void testFocusOnUrlBarIsIgnored() throws Throwable {
         // Set service.
         enableService();
@@ -170,7 +170,7 @@
     }
 
     @Test
-    @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
     public void testUrlBarChangeIgnoredWhenServiceCanSave() throws Throwable {
         // Set service.
         enableService();
@@ -223,7 +223,7 @@
     }
 
     @Test
-    @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
     public void testUrlBarChangeCancelSessionWhenServiceCannotSave() throws Throwable {
         // Set service.
         enableService();
@@ -263,7 +263,7 @@
     }
 
     @Test
-    @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
     public void testUrlBarChangeCancelSessionWhenServiceReturnsNullResponse() throws Throwable {
         // Set service.
         enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
index 07557bf..8cd9a67 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
@@ -113,7 +113,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillSync() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillSync() is enough")
     public void testAutofillAsync() throws Exception {
         skipTestOnCompatMode();
 
@@ -251,7 +251,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillSync() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillSync() is enough")
     public void testAutofillTwoDatasets() throws Exception {
         // Set service.
         enableService();
@@ -324,13 +324,13 @@
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
         autofillManuallyTwoDatasets(true);
     }
 
     @Test
-    @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
     public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
         autofillManuallyTwoDatasets(false);
     }
@@ -402,7 +402,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillCallbacks() is enough")
     public void testAutofillCallbackDisabled() throws Throwable {
         // Set service.
         disableService();
@@ -416,7 +416,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillCallbacks() is enough")
     public void testAutofillCallbackNoDatasets() throws Throwable {
         // Set service.
         enableService();
@@ -437,7 +437,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillCallbacks() is enough")
     public void testAutofillCallbackNoDatasetsButSaveInfo() throws Throwable {
         // Set service.
         enableService();
@@ -628,7 +628,7 @@
     }
 
     @Test
-    @AppModeFull // testSaveNotShown_noUserInput() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSaveNotShown_noUserInput() is enough")
     public void testSaveNotShown_initialValues_noUserInput() throws Throwable {
         // Prepare activitiy.
         mActivity.mUsername.setText("foo");
@@ -653,7 +653,7 @@
     }
 
     @Test
-    @AppModeFull // testSaveNotShown_noUserInput() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSaveNotShown_noUserInput() is enough")
     public void testSaveNotShown_initialValues_noUserInput_serviceDatasets() throws Throwable {
         // Prepare activitiy.
         mActivity.mUsername.setText("foo");
@@ -684,7 +684,7 @@
     }
 
     @Test
-    @AppModeFull // testSaveNotShown_noUserInput() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testSaveNotShown_noUserInput() is enough")
     public void testSaveNotShown_userInputMatchesDatasets() throws Throwable {
         // Prepare activitiy.
         mActivity.mUsername.setText("foo");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
index 4712413..637d8b4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
@@ -67,7 +67,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillOneDataset() is enough")
     public void testAutofillNoDatasets() throws Exception {
         // Set service.
         enableService();
@@ -93,7 +93,7 @@
 
     @Ignore("blocked on b/74793485")
     @Test
-    @AppModeFull // testAutofillOneDataset() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillOneDataset() is enough")
     public void testAutofillOneDataset_usingAppContext() throws Exception {
         autofillOneDatasetTest(true);
     }
@@ -297,7 +297,7 @@
     }
 
     @Test
-    @AppModeFull // testAutofillAndSave() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillAndSave() is enough")
     public void testAutofillAndSave_withExternalViews_loadWebViewFirst() throws Exception {
         // Set service.
         enableService();
@@ -423,7 +423,7 @@
 
     @Test
     @Ignore("blocked on b/69461853")
-    @AppModeFull // testAutofillAndSave() is enough to test ephemeral apps support
+    @AppModeFull(reason = "testAutofillAndSave() is enough")
     public void testAutofillAndSave_withExternalViews_loadExternalViewsFirst() throws Exception {
         // Set service.
         enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
index f1b262f..83a938d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
@@ -17,31 +17,21 @@
 
 import static android.autofillservice.cts.Helper.allowOverlays;
 import static android.autofillservice.cts.Helper.disallowOverlays;
-import static android.provider.Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS;
 
 import android.autofillservice.cts.AbstractAutoFillActivity;
 import android.autofillservice.cts.AutoFillServiceTestCase;
 import android.autofillservice.cts.augmented.CtsAugmentedAutofillService.AugmentedReplier;
 import android.view.autofill.AutofillManager;
 
-import com.android.compatibility.common.util.SettingsStateChangerRule;
-import com.android.compatibility.common.util.SettingsUtils;
-
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.ClassRule;
 
 // Must be public because of the @ClassRule
 public abstract class AugmentedAutofillAutoActivityLaunchTestCase
         <A extends AbstractAutoFillActivity> extends AutoFillServiceTestCase.AutoActivityLaunch<A> {
 
-    @ClassRule
-    public static final SettingsStateChangerRule sFeatureEnabler = new SettingsStateChangerRule(
-            sContext, SettingsUtils.NAMESPACE_GLOBAL, AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
-            Integer.toString(AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM));
-
     protected static AugmentedReplier sAugmentedReplier;
     protected AugmentedUiBot mAugmentedUiBot;
 
@@ -70,6 +60,11 @@
         AugmentedHelper.resetAugmentedService();
     }
 
+    @Override
+    protected int getSmartSuggestionMode() {
+        return AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
+    }
+
     protected void enableAugmentedService() {
         AugmentedHelper.setAugmentedService(CtsAugmentedAutofillService.SERVICE_NAME);
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
index a4d189f..9deb6ed 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
@@ -26,6 +26,7 @@
 import android.autofillservice.cts.LoginActivity;
 import android.autofillservice.cts.OneTimeCancellationSignalListener;
 import android.autofillservice.cts.augmented.CtsAugmentedAutofillService.AugmentedFillRequest;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.uiautomator.UiObject2;
 import android.view.View;
 import android.view.autofill.AutofillId;
@@ -52,6 +53,7 @@
     }
 
     @Test
+    @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
     public void testAutoFill_neitherServiceCanAutofill() throws Exception {
         // Set services
         enableService();
@@ -118,6 +120,7 @@
     }
 
     @Test
+    @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
     public void testAutoFill_mainServiceReturnedNull_augmentedAutofillTwoFields() throws Exception {
         // Set services
         enableService();
@@ -158,6 +161,7 @@
 
     @Ignore("blocked on b/122728762")
     @Test
+    @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
     public void testCancellationSignalCalledAfterTimeout() throws Exception {
         // Set services
         enableService();
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index ebbd555..32b5932 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -82,12 +82,6 @@
 LOCAL_JNI_SHARED_LIBRARIES := \
 	libctscamera2_jni \
 	libnativehelper_compat_libc++ \
-	libdynamic_depth \
-	libimage_io \
-	libxml2 \
-	libandroidicu \
-	libbase \
-	libc++ \
 
 LOCAL_NDK_STL_VARIANT := c++_shared
 
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
index dda68c8..94f7ca3 100644
--- a/tests/camera/AndroidTest.xml
+++ b/tests/camera/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="camera" />
     <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="CtsCameraTestCases.apk" />
diff --git a/tests/camera/libctscamera2jni/Android.mk b/tests/camera/libctscamera2jni/Android.mk
index e9c301e..798674b 100644
--- a/tests/camera/libctscamera2jni/Android.mk
+++ b/tests/camera/libctscamera2jni/Android.mk
@@ -35,15 +35,18 @@
 # Flags to avoid warnings from DNG SDK
 LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
 LOCAL_CFLAGS += -Wno-unused-value -Wno-unused-variable
+# Flags related to dynamic depth
+LOCAL_CFLAGS += -Wno-ignored-qualifiers -DSTATIC_LIBXML=1
 
 LOCAL_STATIC_LIBRARIES := libdng_sdk_validate libjpeg_static_ndk
+# Dynamic depth libraries
+LOCAL_STATIC_LIBRARIES += libdynamic_depth_ndk libimage_io_ndk libbase_ndk libxml2_ndk
 LOCAL_SHARED_LIBRARIES := libandroid \
     libnativehelper_compat_libc++ \
     liblog \
     libcamera2ndk \
     libmediandk \
     libz \
-    libdl \
 
 # NDK build, shared C++ runtime
 LOCAL_SDK_VERSION := current
diff --git a/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp b/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
index a1d4b83..fbc63ef 100644
--- a/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
+++ b/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
@@ -17,11 +17,9 @@
 #define LOG_TAG "DYNAMIC-DEPTH-JNI"
 #include <jni.h>
 #include <log/log.h>
-#include <dlfcn.h>
+#include <dynamic_depth/depth_jpeg.h>
 
-typedef int32_t (*validate_dynamic_depth_buffer) (const char *, size_t);
-static const char *kDynamicDepthLibraryName = "libdynamic_depth.so";
-static const char *kDynamicDepthValidateFunction = "ValidateAndroidDynamicDepthBuffer";
+using namespace dynamic_depth;
 
 extern "C" jboolean
 Java_android_hardware_camera2_cts_ImageReaderTest_validateDynamicDepthNative(
@@ -34,23 +32,8 @@
         return JNI_FALSE;
     }
 
-    void* depthLibHandle = dlopen(kDynamicDepthLibraryName, RTLD_NOW | RTLD_LOCAL);
-    if (depthLibHandle == nullptr) {
-        ALOGE("Failed to load dynamic depth library!");
-        return JNI_FALSE;
-    }
-
-    validate_dynamic_depth_buffer validate = reinterpret_cast<validate_dynamic_depth_buffer> (
-            dlsym(depthLibHandle, kDynamicDepthValidateFunction));
-    if (validate == nullptr) {
-        ALOGE("Failed to link to dynamic depth validate function!");
-        dlclose(depthLibHandle);
-        return JNI_FALSE;
-    }
-
-    auto ret = (validate(reinterpret_cast<const char *> (buffer), bufferLength) == 0) ?
-            JNI_TRUE : JNI_FALSE;
-    dlclose(depthLibHandle);
+    auto ret = (ValidateAndroidDynamicDepthBuffer(reinterpret_cast<const char *> (buffer),
+                bufferLength) == 0) ? JNI_TRUE : JNI_FALSE;
 
     return ret;
 }
diff --git a/tests/camera/libctscamera2jni/native-camera-jni.cpp b/tests/camera/libctscamera2jni/native-camera-jni.cpp
index 9ab8222..7dac96f 100644
--- a/tests/camera/libctscamera2jni/native-camera-jni.cpp
+++ b/tests/camera/libctscamera2jni/native-camera-jni.cpp
@@ -653,22 +653,46 @@
     }
 
     int64_t getMinFrameDurationFor(int64_t format, int64_t width, int64_t height) {
-        return getDurationFor(ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, format, width, height);
+        int32_t minFrameDurationTag = (format == AIMAGE_FORMAT_HEIC) ?
+                ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS :
+                ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+        return getDurationFor(minFrameDurationTag, format, width, height);
     }
 
     int64_t getStallDurationFor(int64_t format, int64_t width, int64_t height) {
-        return getDurationFor(ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS, format, width, height);
+        int32_t stallDurationTag = (format == AIMAGE_FORMAT_HEIC) ?
+                ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS :
+                ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS;
+        return getDurationFor(stallDurationTag, format, width, height);
     }
 
     bool getMaxSizeForFormat(int32_t format, int32_t *width, int32_t *height) {
         ACameraMetadata_const_entry entry;
-        ACameraMetadata_getConstEntry(mChars,
-                ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
+
+        int32_t streamConfigTag, streamConfigOutputTag;
+        switch (format) {
+            case AIMAGE_FORMAT_HEIC:
+                streamConfigTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS;
+                streamConfigOutputTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT;
+                break;
+            case AIMAGE_FORMAT_JPEG:
+            case AIMAGE_FORMAT_Y8:
+            default:
+                streamConfigTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+                streamConfigOutputTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+                break;
+        }
+
         bool supported = false;
-        int32_t w = 0, h = 0;
+        camera_status_t status = ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
+        if (status == ACAMERA_ERROR_METADATA_NOT_FOUND) {
+            return supported;
+        }
+
+       int32_t w = 0, h = 0;
         for (uint32_t i = 0; i < entry.count; i += 4) {
             if (entry.data.i32[i] == format &&
-                    entry.data.i32[i+3] == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    entry.data.i32[i+3] == streamConfigOutputTag &&
                     entry.data.i32[i+1] * entry.data.i32[i+2] > w * h) {
                 w = entry.data.i32[i+1];
                 h = entry.data.i32[i+2];
@@ -685,11 +709,25 @@
 
     bool isSizeSupportedForFormat(int32_t format, int32_t width, int32_t height) {
         ACameraMetadata_const_entry entry;
-        ACameraMetadata_getConstEntry(mChars,
-                ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
+
+        int32_t streamConfigTag, streamConfigOutputTag;
+        switch (format) {
+            case AIMAGE_FORMAT_HEIC:
+                streamConfigTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS;
+                streamConfigOutputTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT;
+                break;
+            case AIMAGE_FORMAT_JPEG:
+            case AIMAGE_FORMAT_Y8:
+            default:
+                streamConfigTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+                streamConfigOutputTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+                break;
+        }
+
+        ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
         for (uint32_t i = 0; i < entry.count; i += 4) {
             if (entry.data.i32[i] == format &&
-                    entry.data.i32[i+3] == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    entry.data.i32[i+3] == streamConfigOutputTag &&
                     entry.data.i32[i+1] == width &&
                     entry.data.i32[i+2] == height) {
                 return true;
@@ -702,7 +740,9 @@
         if (tag != ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS &&
                 tag != ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS &&
                 tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS &&
-                tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS) {
+                tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS &&
+                tag != ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS &&
+                tag != ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS) {
             return -1;
         }
         ACameraMetadata_const_entry entry;
@@ -2860,6 +2900,7 @@
                 testHeight = TEST_HEIGHT;
                 break;
             case AIMAGE_FORMAT_Y8:
+            case AIMAGE_FORMAT_HEIC:
                 if (!staticInfo.getMaxSizeForFormat(format, &testWidth, &testHeight)) {
                     // This isn't an error condition: device does't support this
                     // format.
@@ -2956,13 +2997,13 @@
         }
 
         int64_t minFrameDurationNs = staticInfo.getMinFrameDurationFor(
-                AIMAGE_FORMAT_JPEG, TEST_WIDTH, TEST_HEIGHT);
+                format, testWidth, testHeight);
         if (minFrameDurationNs < 0) {
             LOG_ERROR(errorString, "Get camera %s minFrameDuration failed", cameraId);
             goto cleanup;
         }
-        int64_t stallDurationNs = staticInfo.getStallDurationFor(
-                AIMAGE_FORMAT_JPEG, TEST_WIDTH, TEST_HEIGHT);
+        int64_t stallDurationNs = (format == AIMAGE_FORMAT_Y8) ? 0 :
+                staticInfo.getStallDurationFor(format, testWidth, testHeight);
         if (stallDurationNs < 0) {
             LOG_ERROR(errorString, "Get camera %s stallDuration failed", cameraId);
             goto cleanup;
@@ -3053,6 +3094,15 @@
 
 extern "C" jboolean
 Java_android_hardware_camera2_cts_NativeImageReaderTest_\
+testHeicNative(
+        JNIEnv* env, jclass /*clazz*/, jstring jOutPath) {
+    ALOGV("%s", __FUNCTION__);
+    return nativeImageReaderTestBase(env, jOutPath, AIMAGE_FORMAT_HEIC,
+            ImageReaderListener::validateImageCb);
+}
+
+extern "C" jboolean
+Java_android_hardware_camera2_cts_NativeImageReaderTest_\
 testImageReaderCloseAcquiredImagesNative(
         JNIEnv* env, jclass /*clazz*/) {
     ALOGV("%s", __FUNCTION__);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index b095b8a..8eff888 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -187,6 +187,7 @@
 
             boolean isMonochromeWithY8 = arrayContains(actualCapabilities, MONOCHROME)
                     && arrayContains(outputFormats, ImageFormat.Y8);
+            boolean supportHeic = arrayContains(outputFormats, ImageFormat.HEIC);
 
             assertArrayContains(
                     String.format("No valid YUV_420_888 preview formats found for: ID %s",
@@ -202,6 +203,7 @@
             Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888);
             Size[] y8Sizes = config.getOutputSizes(ImageFormat.Y8);
             Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG);
+            Size[] heicSizes = config.getOutputSizes(ImageFormat.HEIC);
             Size[] privateSizes = config.getOutputSizes(ImageFormat.PRIVATE);
 
             CameraTestUtils.assertArrayNotEmpty(yuvSizes,
@@ -224,6 +226,12 @@
                         "Required FULLHD size not found for format %x for: ID %s",
                         ImageFormat.JPEG, mIds[counter]), jpegSizes,
                         new Size[] {FULLHD, FULLHD_ALT});
+                if (supportHeic) {
+                    assertArrayContainsAnyOf(String.format(
+                            "Required FULLHD size not found for format %x for: ID %s",
+                            ImageFormat.HEIC, mIds[counter]), heicSizes,
+                            new Size[] {FULLHD, FULLHD_ALT});
+                }
             }
 
             if (activeArraySize.getWidth() >= HD.getWidth() &&
@@ -231,6 +239,11 @@
                 assertArrayContains(String.format(
                         "Required HD size not found for format %x for: ID %s",
                         ImageFormat.JPEG, mIds[counter]), jpegSizes, HD);
+                if (supportHeic) {
+                    assertArrayContains(String.format(
+                            "Required HD size not found for format %x for: ID %s",
+                            ImageFormat.HEIC, mIds[counter]), heicSizes, HD);
+                }
             }
 
             if (activeArraySize.getWidth() >= VGA.getWidth() &&
@@ -238,6 +251,11 @@
                 assertArrayContains(String.format(
                         "Required VGA size not found for format %x for: ID %s",
                         ImageFormat.JPEG, mIds[counter]), jpegSizes, VGA);
+                if (supportHeic) {
+                    assertArrayContains(String.format(
+                            "Required VGA size not found for format %x for: ID %s",
+                            ImageFormat.HEIC, mIds[counter]), heicSizes, VGA);
+                }
             }
 
             if (activeArraySize.getWidth() >= QVGA.getWidth() &&
@@ -245,6 +263,12 @@
                 assertArrayContains(String.format(
                         "Required QVGA size not found for format %x for: ID %s",
                         ImageFormat.JPEG, mIds[counter]), jpegSizes, QVGA);
+                if (supportHeic) {
+                    assertArrayContains(String.format(
+                            "Required QVGA size not found for format %x for: ID %s",
+                            ImageFormat.HEIC, mIds[counter]), heicSizes, QVGA);
+                }
+
             }
 
             ArrayList<Size> jpegSizesList = new ArrayList<>(Arrays.asList(jpegSizes));
@@ -1363,6 +1387,8 @@
                 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
             Rect activeArray = c.get(
                 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+            float jpegAspectRatioThreshold = .01f;
+            boolean jpegSizeMatch = false;
 
             // Verify pre-correction array encloses active array
             mCollector.expectTrue("preCorrectionArray [" + precorrectionArray.left + ", " +
@@ -1392,6 +1418,7 @@
                         hasDepth16);
                 if (hasDepth16) {
                     Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16);
+                    Size[] jpegSizes = configs.getOutputSizes(ImageFormat.JPEG);
                     mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!",
                             depthSizes != null && depthSizes.length > 0);
                     if (depthSizes != null) {
@@ -1408,6 +1435,24 @@
                             mCollector.expectTrue("Non-negative stall duration for depth size "
                                     + depthSize + " expected, got " + stallDuration,
                                     stallDuration >= 0);
+                            if ((jpegSizes != null) && (!jpegSizeMatch)) {
+                                for (Size jpegSize : jpegSizes) {
+                                    if (jpegSize.equals(depthSize)) {
+                                        jpegSizeMatch = true;
+                                        break;
+                                    } else {
+                                        float depthAR = (float) depthSize.getWidth() /
+                                                (float) depthSize.getHeight();
+                                        float jpegAR = (float) jpegSize.getWidth() /
+                                                (float) jpegSize.getHeight();
+                                        if (Math.abs(depthAR - jpegAR) <=
+                                                jpegAspectRatioThreshold) {
+                                            jpegSizeMatch = true;
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
                         }
                     }
                 }
@@ -1446,6 +1491,8 @@
                     mCollector.expectTrue("Supports DEPTH_JPEG " +
                             "but no sizes for DEPTH_JPEG supported!",
                             depthJpegSizes != null && depthJpegSizes.length > 0);
+                    mCollector.expectTrue("Supports DEPTH_JPEG but there are no JPEG sizes with" +
+                            " matching DEPTH16 aspect ratio", jpegSizeMatch);
                     if (depthJpegSizes != null) {
                         for (Size depthJpegSize : depthJpegSizes) {
                             mCollector.expectTrue("All depth jpeg sizes must be nonzero",
@@ -1462,6 +1509,11 @@
                                     stallDuration >= 0);
                         }
                     }
+                } else {
+                    boolean canSupportDynamicDepth = jpegSizeMatch && !depthIsExclusive;
+                    mCollector.expectTrue("Device must support DEPTH_JPEG, please check whether " +
+                            "library libdepthphoto.so is part of the device PRODUCT_PACKAGES",
+                            !canSupportDynamicDepth);
                 }
 
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
index af6e5e0..0716c24 100644
--- a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
@@ -91,7 +91,7 @@
         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
 
         prepareStillCaptureAndStartPreview(previewRequest, stillCaptureRequest,
-                previewSize, stillSize, resultListener, imageListener);
+                previewSize, stillSize, resultListener, imageListener, false /*isHeic*/);
 
         CaptureResult result = resultListener.getCaptureResult(WAIT_FOR_FRAMES_TIMEOUT_MS);
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
index 3ed4fdb..b8cf221 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -204,6 +204,17 @@
         }
     }
 
+    public void testHeic() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing heic capture for Camera " + id);
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.HEIC, /*repeating*/false);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
 
     public void testRepeatingJpeg() throws Exception {
         for (String id : mCameraIds) {
@@ -243,6 +254,18 @@
         }
     }
 
+    public void testRepeatingHeic() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing repeating heic capture for Camera " + id);
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.HEIC, /*repeating*/true);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
     public void testLongProcessingRepeatingRaw() throws Exception {
         for (String id : mCameraIds) {
             try {
@@ -367,6 +390,32 @@
     }
 
     /**
+     * If the camera device advertises the SECURE_IAMGE_DATA capability, test
+     * ImageFormat.PRIVATE + PROTECTED usage capture by using ImageReader with the
+     * ImageReader factory method that has usage flag argument, and uses a custom usage flag.
+     */
+    public void testImageReaderPrivateWithProtectedUsageFlag() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Private format and protected usage testing for camera " + id);
+                if (!mAllStaticInfo.get(id).isCapabilitySupported(
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA)) {
+                    Log.i(TAG, "Camera " + id +
+                            " does not support secure image data capability, skipping");
+
+                    continue;
+                }
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.PRIVATE, /*setUsageFlag*/ true,
+                        HardwareBuffer.USAGE_PROTECTED_CONTENT, /*repeating*/ true,
+                        /*checkSession*/ true, /*validateImageData*/ false);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    /**
      * Test two image stream (YUV420_888 and RAW_SENSOR) capture by using ImageReader with the
      * ImageReader factory method that has usage flag argument.
      *
@@ -930,11 +979,23 @@
     }
 
     private void bufferFormatTestByCamera(int format, boolean repeating) throws Exception {
-        bufferFormatTestByCamera(format, repeating, /*checkSession*/ false);
+        bufferFormatTestByCamera(format, /*setUsageFlag*/ false,
+                HardwareBuffer.USAGE_CPU_READ_OFTEN, repeating,
+                /*checkSession*/ false, /*validateImageData*/ true);
     }
 
     private void bufferFormatTestByCamera(int format, boolean repeating, boolean checkSession)
             throws Exception {
+        bufferFormatTestByCamera(format, /*setUsageFlag*/ false,
+                HardwareBuffer.USAGE_CPU_READ_OFTEN,
+                repeating, checkSession, /*validateImageData*/true);
+    }
+
+    private void bufferFormatTestByCamera(int format, boolean setUsageFlag, long usageFlag,
+            // TODO: Consider having some sort of test configuration class passed to reduce the
+            //       proliferation of parameters ?
+            boolean repeating, boolean checkSession, boolean validateImageData)
+            throws Exception {
         Size[] availableSizes = mStaticInfo.getAvailableSizesForFormatChecked(format,
                 StaticMetadata.StreamDirection.Output);
 
@@ -948,7 +1009,11 @@
 
                 // Create ImageReader.
                 mListener  = new SimpleImageListener();
-                createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mListener);
+                if (setUsageFlag) {
+                    createDefaultImageReader(sz, format, MAX_NUM_IMAGES, usageFlag, mListener);
+                } else {
+                    createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mListener);
+                }
 
                 if (checkSession) {
                     assertTrue("Camera capture session validation for format: " + format +
@@ -962,8 +1027,10 @@
 
                 int numFrameVerified = repeating ? NUM_FRAME_VERIFIED : 1;
 
-                // Validate images.
-                validateImage(sz, format, numFrameVerified, repeating);
+                if (validateImageData) {
+                    // Validate images.
+                    validateImage(sz, format, numFrameVerified, repeating);
+                }
 
                 // Validate capture result.
                 validateCaptureResult(format, sz, listener, numFrameVerified);
@@ -1191,7 +1258,6 @@
 
     /** Load dynamic depth validation jni on initialization */
     static {
-        System.loadLibrary("dynamic_depth");
         System.loadLibrary("ctscamera2_jni");
     }
     /**
diff --git a/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java
index 4eee734..ce5f946 100644
--- a/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java
@@ -43,6 +43,11 @@
                 testY8Native(mDebugFileNameBase));
     }
 
+    public void testHeic() {
+        assertTrue("testHeic fail, see log for details",
+                testHeicNative(mDebugFileNameBase));
+    }
+
     public void testImageReaderCloseAcquiredImages() {
         assertTrue("testImageReaderClose fail, see log for details",
                 testImageReaderCloseAcquiredImagesNative());
@@ -50,5 +55,6 @@
 
     private static native boolean testJpegNative(String filePath);
     private static native boolean testY8Native(String filePath);
+    private static native boolean testHeicNative(String filePath);
     private static native boolean testImageReaderCloseAcquiredImagesNative();
 }
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 0fa1741..fbb8cce 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -363,7 +363,8 @@
 
                     readers = prepareStillCaptureAndStartPreview(previewBuilder, captureBuilder,
                             mOrderedPreviewSizes.get(0), imageSizes, formats,
-                            previewResultListener, NUM_MAX_IMAGES, imageListeners);
+                            previewResultListener, NUM_MAX_IMAGES, imageListeners,
+                            false /*isHeic*/);
 
                     if (addPreviewDelay) {
                         Thread.sleep(500);
@@ -1141,11 +1142,13 @@
      * @param resultListener Capture result listener
      * @param maxNumImages The max number of images set to the image reader
      * @param imageListeners The single capture capture image listeners
+     * @param isHeic Capture HEIC image if true, JPEG image if false
      */
     private ImageReader[] prepareStillCaptureAndStartPreview(
             CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest,
             Size previewSz, Size[] captureSizes, int[] formats, CaptureCallback resultListener,
-            int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners)
+            int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners,
+            boolean isHeic)
             throws Exception {
 
         if ((captureSizes == null) || (formats == null) || (imageListeners == null) &&
diff --git a/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
index 8fa1077..1420078 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
@@ -116,6 +116,24 @@
     }
 
     /**
+     * Test YUV_420_888 -> HEIC with maximal supported sizes
+     */
+    @Test
+    public void testBasicYuvToHeicReprocessing() throws Exception {
+        for (String id : mCameraIds) {
+            if (!isYuvReprocessSupported(id)) {
+                continue;
+            }
+            if (!mAllStaticInfo.get(id).isHeicSupported()) {
+                continue;
+            }
+
+            // YUV_420_888 -> HEIC must be supported.
+            testBasicReprocessing(id, ImageFormat.YUV_420_888, ImageFormat.HEIC);
+        }
+    }
+
+    /**
      * Test OPAQUE -> YUV_420_888 with maximal supported sizes
      */
     @Test
@@ -146,6 +164,24 @@
     }
 
     /**
+     * Test OPAQUE -> HEIC with maximal supported sizes
+     */
+    @Test
+    public void testBasicOpaqueToHeicReprocessing() throws Exception {
+        for (String id : mCameraIds) {
+            if (!isOpaqueReprocessSupported(id)) {
+                continue;
+            }
+            if (!mAllStaticInfo.get(id).isHeicSupported()) {
+                continue;
+            }
+
+            // OPAQUE -> HEIC must be supported.
+            testBasicReprocessing(id, ImageFormat.PRIVATE, ImageFormat.HEIC);
+        }
+    }
+
+    /**
      * Test all supported size and format combinations.
      */
     @Test(timeout=60*60*1000) // timeout = 60 mins for long running tests
@@ -978,7 +1014,7 @@
                 Image image = getReprocessOutputImageReaderListener().getImage(CAPTURE_TIMEOUT_MS);
                 verifyJpegKeys(image, reprocessResults[i], reprocessOutputSize,
                         testThumbnailSizes[i], EXIF_TEST_DATA[i], mStaticInfo, mCollector,
-                        mDebugFileNameBase);
+                        mDebugFileNameBase, ImageFormat.JPEG);
                 image.close();
 
             }
@@ -1391,6 +1427,9 @@
             case ImageFormat.JPEG:
                 filename += ".jpg";
                 break;
+            case ImageFormat.HEIC:
+                filename += ".heic";
+                break;
             case ImageFormat.NV16:
             case ImageFormat.NV21:
             case ImageFormat.YUV_420_888:
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index 995a2c7..a519101 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -254,8 +254,10 @@
     private void setupConfigurationTargets(List<MandatoryStreamInformation> streamsInfo,
             List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
             List<ImageReader> yuvTargets, List<ImageReader> y8Targets,
-            List<ImageReader> rawTargets, List<OutputConfiguration> outputConfigs,
-            int numBuffers, boolean substituteY8, MandatoryStreamInformation overrideStreamInfo,
+            List<ImageReader> rawTargets, List<ImageReader> heicTargets,
+            List<OutputConfiguration> outputConfigs,
+            int numBuffers, boolean substituteY8, boolean substituteHeic,
+            MandatoryStreamInformation overrideStreamInfo,
             List<String> overridePhysicalCameraIds, List<Size> overridePhysicalCameraSizes) {
 
         ImageDropperListener imageDropperListener = new ImageDropperListener();
@@ -267,6 +269,8 @@
             int format = streamInfo.getFormat();
             if (substituteY8 && (format == ImageFormat.YUV_420_888)) {
                 format = ImageFormat.Y8;
+            } else if (substituteHeic && (format == ImageFormat.JPEG)) {
+                format = ImageFormat.HEIC;
             }
             Surface newSurface;
             Size[] availableSizes = new Size[streamInfo.getAvailableSizes().size()];
@@ -345,6 +349,18 @@
                         }
                         break;
                     }
+                    case ImageFormat.HEIC: {
+                        ImageReader target = ImageReader.newInstance(targetSize.getWidth(),
+                                targetSize.getHeight(), format, numBuffers);
+                        target.setOnImageAvailableListener(imageDropperListener, mHandler);
+                        OutputConfiguration config = new OutputConfiguration(target.getSurface());
+                        if (numConfigs > 1) {
+                            config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+                        }
+                        outputConfigs.add(config);
+                        heicTargets.add(target);
+                        break;
+                    }
                     default:
                         fail("Unknown output format " + format);
                 }
@@ -366,13 +382,36 @@
             }
         }
 
+        // Check whether substituting JPEG format with HEIC format
+        boolean substituteHeic = false;
+        if (mStaticInfo.isHeicSupported()) {
+            List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
+            for (MandatoryStreamInformation streamInfo : streamsInfo) {
+                if (streamInfo.getFormat() == ImageFormat.JPEG) {
+                    substituteHeic = true;
+                    break;
+                }
+            }
+        }
+
         // Test camera output combination
         Log.i(TAG, "Testing mandatory stream combination: " + combination.getDescription() +
                 " on camera: " + cameraId);
-        testMandatoryStreamCombination(cameraId, combination, /*substituteY8*/false);
+        testMandatoryStreamCombination(cameraId, combination, /*substituteY8*/false,
+                /*substituteHeic*/false);
 
         if (substituteY8) {
-            testMandatoryStreamCombination(cameraId, combination, substituteY8);
+            Log.i(TAG, "Testing mandatory stream combination: " + combination.getDescription() +
+                    " on camera: " + cameraId + " with Y8");
+            testMandatoryStreamCombination(cameraId, combination, /*substituteY8*/true,
+                    /*substituteHeic*/false);
+        }
+
+        if (substituteHeic) {
+            Log.i(TAG, "Testing mandatory stream combination: " + combination.getDescription() +
+                    " on camera: " + cameraId + " with HEIC");
+            testMandatoryStreamCombination(cameraId, combination,
+                    /*substituteY8*/false, /*substituteHeic*/true);
         }
 
         // Test substituting YUV_888/RAW with physical streams for logical camera
@@ -383,7 +422,7 @@
             testMultiCameraOutputCombination(cameraId, combination, /*substituteY8*/false);
 
             if (substituteY8) {
-                testMultiCameraOutputCombination(cameraId, combination, substituteY8);
+                testMultiCameraOutputCombination(cameraId, combination, /*substituteY8*/true);
             }
         }
     }
@@ -441,10 +480,12 @@
             List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
             List<ImageReader> y8Targets = new ArrayList<ImageReader>();
             List<ImageReader> rawTargets = new ArrayList<ImageReader>();
+            List<ImageReader> heicTargets = new ArrayList<ImageReader>();
 
             setupConfigurationTargets(streamsInfo, privTargets, jpegTargets, yuvTargets,
-                    y8Targets, rawTargets, outputConfigs, MIN_RESULT_COUNT, substituteY8,
-                    streamInfo, physicalCamerasForSize, physicalCameraSizes);
+                    y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT,
+                    substituteY8, /*substituteHeic*/false, streamInfo, physicalCamerasForSize,
+                    physicalCameraSizes);
 
             boolean haveSession = false;
             try {
@@ -516,7 +557,8 @@
     }
 
     private void testMandatoryStreamCombination(String cameraId,
-            MandatoryStreamCombination combination, boolean substituteY8) throws Exception {
+            MandatoryStreamCombination combination,
+            boolean substituteY8, boolean substituteHeic) throws Exception {
 
         // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS
         final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 2000 : 1000;
@@ -529,9 +571,11 @@
         List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
         List<ImageReader> y8Targets = new ArrayList<ImageReader>();
         List<ImageReader> rawTargets = new ArrayList<ImageReader>();
+        List<ImageReader> heicTargets = new ArrayList<ImageReader>();
 
         setupConfigurationTargets(combination.getStreamsInformation(), privTargets, jpegTargets,
-                yuvTargets, y8Targets, rawTargets, outputConfigs, MIN_RESULT_COUNT, substituteY8,
+                yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT,
+                substituteY8, substituteHeic,
                 null /*overrideStreamInfo*/, null /*overridePhysicalCameraIds*/,
                 null /* overridePhysicalCameraSizes) */);
 
@@ -600,6 +644,9 @@
         for (ImageReader target : rawTargets) {
             target.close();
         }
+        for (ImageReader target : heicTargets) {
+            target.close();
+        }
     }
 
     /**
@@ -635,26 +682,42 @@
     private void testMandatoryReprocessableStreamCombination(String cameraId,
             MandatoryStreamCombination combination) {
         // Test reprocess stream combination
-        testMandatoryReprocessableStreamCombination(cameraId, combination, /*substituteY8*/false);
+        testMandatoryReprocessableStreamCombination(cameraId, combination,
+                /*substituteY8*/false, /*substituteHeic*/false);
 
         // Test substituting YUV_888 format with Y8 format in reprocess stream combination.
         if (mStaticInfo.isMonochromeWithY8()) {
             List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
-            boolean hasY8 = false;
+            boolean substituteY8 = false;
             for (MandatoryStreamInformation streamInfo : streamsInfo) {
                 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) {
-                    hasY8 = true;
-                    break;
+                    substituteY8 = true;
                 }
             }
-            if (hasY8) {
-                testMandatoryReprocessableStreamCombination(cameraId, combination, hasY8);
+            if (substituteY8) {
+                testMandatoryReprocessableStreamCombination(cameraId, combination,
+                        /*substituteY8*/true, /*substituteHeic*/false);
+            }
+        }
+
+        if (mStaticInfo.isHeicSupported()) {
+            List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
+            boolean substituteHeic = false;
+            for (MandatoryStreamInformation streamInfo : streamsInfo) {
+                if (streamInfo.getFormat() == ImageFormat.JPEG) {
+                    substituteHeic = true;
+                }
+            }
+            if (substituteHeic) {
+                testMandatoryReprocessableStreamCombination(cameraId, combination,
+                        /*substituteY8*/false, /*substituteHeic*/true);
             }
         }
     }
 
     private void testMandatoryReprocessableStreamCombination(String cameraId,
-            MandatoryStreamCombination combination, boolean substituteY8) {
+            MandatoryStreamCombination combination, boolean substituteY8,
+            boolean substituteHeic) {
 
         final int TIMEOUT_FOR_RESULT_MS = 3000;
         final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3;
@@ -664,6 +727,7 @@
         List<ImageReader> yuvTargets = new ArrayList<>();
         List<ImageReader> y8Targets = new ArrayList<>();
         List<ImageReader> rawTargets = new ArrayList<>();
+        List<ImageReader> heicTargets = new ArrayList<>();
         ArrayList<Surface> outputSurfaces = new ArrayList<>();
         List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
         ImageReader inputReader = null;
@@ -685,13 +749,17 @@
             inputFormat = ImageFormat.Y8;
         }
 
+        Log.i(TAG, "testMandatoryReprocessableStreamCombination: " +
+                combination.getDescription() + ", substituteY8 = " + substituteY8 +
+                ", substituteHeic = " + substituteHeic);
         try {
             // The second stream information entry is the ZSL stream, which is configured
             // separately.
             setupConfigurationTargets(streamInfo.subList(2, streamInfo.size()), privTargets,
-                    jpegTargets, yuvTargets, y8Targets, rawTargets, outputConfigs,
-                    NUM_REPROCESS_CAPTURES_PER_CONFIG, substituteY8,  null /*overrideStreamInfo*/,
-                    null /*overridePhysicalCameraIds*/, null /* overridePhysicalCameraSizes) */);
+                    jpegTargets, yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs,
+                    NUM_REPROCESS_CAPTURES_PER_CONFIG, substituteY8,  substituteHeic,
+                    null /*overrideStreamInfo*/, null /*overridePhysicalCameraIds*/,
+                    null /* overridePhysicalCameraSizes) */);
 
             outputSurfaces.ensureCapacity(outputConfigs.size());
             for (OutputConfiguration config : outputConfigs) {
@@ -709,7 +777,8 @@
             final boolean useY8 = inputIsY8 || y8Targets.size() > 0;
             final int totalNumReprocessCaptures =  NUM_REPROCESS_CAPTURES_PER_CONFIG * (
                     ((inputIsYuv || inputIsY8) ? 1 : 0) +
-                    jpegTargets.size() + (useYuv ? yuvTargets.size() : y8Targets.size()));
+                    (substituteHeic ? heicTargets.size() : jpegTargets.size()) +
+                    (useYuv ? yuvTargets.size() : y8Targets.size()));
 
             // It needs 1 input buffer for each reprocess capture + the number of buffers
             // that will be used as outputs.
@@ -750,6 +819,10 @@
                 reprocessOutputs.add(reader.getSurface());
             }
 
+            for (ImageReader reader : heicTargets) {
+                reprocessOutputs.add(reader.getSurface());
+            }
+
             for (ImageReader reader : yuvTargets) {
                 reprocessOutputs.add(reader.getSurface());
             }
@@ -803,6 +876,10 @@
                 target.close();
             }
 
+            for (ImageReader target : heicTargets) {
+                target.close();
+            }
+
             if (inputReader != null) {
                 inputReader.close();
             }
@@ -1916,6 +1993,7 @@
         static final int YUV  = ImageFormat.YUV_420_888;
         static final int RAW  = ImageFormat.RAW_SENSOR;
         static final int Y8   = ImageFormat.Y8;
+        static final int HEIC = ImageFormat.HEIC;
 
         // Max resolution indices
         static final int PREVIEW = 0;
@@ -1933,6 +2011,7 @@
                     StaticMetadata.StreamDirection.Output);
             Size[] jpegSizes = sm.getJpegOutputSizesChecked();
             Size[] rawSizes = sm.getRawOutputSizesChecked();
+            Size[] heicSizes = sm.getHeicOutputSizesChecked();
 
             Size maxPreviewSize = getMaxPreviewSize(context, cameraId);
 
@@ -1975,6 +2054,13 @@
                     maxY8Sizes[MAXIMUM] = CameraTestUtils.getMaxSize(y8Sizes);
                     maxY8Sizes[VGA] = vgaSize;
                 }
+
+                if (sm.isHeicSupported()) {
+                    maxHeicSizes[PREVIEW] = getMaxSize(heicSizes, maxPreviewSize);
+                    maxHeicSizes[RECORD] = getMaxRecordingSize(cameraId);
+                    maxHeicSizes[MAXIMUM] = CameraTestUtils.getMaxSize(heicSizes);
+                    maxHeicSizes[VGA] = vgaSize;
+                }
             }
 
             Size[] privInputSizes = configs.getInputSizes(ImageFormat.PRIVATE);
@@ -1992,6 +2078,7 @@
         public final Size[] maxJpegSizes = new Size[RESOLUTION_COUNT];
         public final Size[] maxYuvSizes = new Size[RESOLUTION_COUNT];
         public final Size[] maxY8Sizes = new Size[RESOLUTION_COUNT];
+        public final Size[] maxHeicSizes = new Size[RESOLUTION_COUNT];
         public final Size maxRawSize;
         // TODO: support non maximum reprocess input.
         public final Size maxInputPrivSize;
@@ -2119,9 +2206,10 @@
             List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
             List<ImageReader> y8Targets = new ArrayList<ImageReader>();
             List<ImageReader> rawTargets = new ArrayList<ImageReader>();
+            List<ImageReader> heicTargets = new ArrayList<ImageReader>();
 
             setupConfigurationTargets(config, maxSizes, privTargets, jpegTargets, yuvTargets,
-                    y8Targets, rawTargets, outputConfigs, MIN_RESULT_COUNT, i,
+                    y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT, i,
                     physicalCamerasForSize, physicalCameraSizes);
 
             boolean haveSession = false;
@@ -2196,7 +2284,8 @@
     private void setupConfigurationTargets(int[] configs, MaxStreamSizes maxSizes,
             List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
             List<ImageReader> yuvTargets, List<ImageReader> y8Targets,
-            List<ImageReader> rawTargets, List<OutputConfiguration> outputConfigs, int numBuffers,
+            List<ImageReader> rawTargets, List<ImageReader> heicTargets,
+            List<OutputConfiguration> outputConfigs, int numBuffers,
             int overrideStreamIndex, List<String> overridePhysicalCameraIds,
             List<Size> overridePhysicalCameraSizes) {
 
@@ -2241,6 +2330,20 @@
                         jpegTargets.add(target);
                         break;
                     }
+                    case HEIC: {
+                        Size targetSize = (numConfigs == 1) ? maxSizes.maxHeicSizes[sizeLimit] :
+                                overridePhysicalCameraSizes.get(j);
+                        ImageReader target = ImageReader.newInstance(
+                            targetSize.getWidth(), targetSize.getHeight(), HEIC, numBuffers);
+                        target.setOnImageAvailableListener(imageDropperListener, mHandler);
+                        OutputConfiguration config = new OutputConfiguration(target.getSurface());
+                        if (numConfigs > 1) {
+                            config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+                        }
+                        outputConfigs.add(config);
+                        heicTargets.add(target);
+                        break;
+                    }
                     case YUV: {
                         Size targetSize = (numConfigs == 1) ? maxSizes.maxYuvSizes[sizeLimit] :
                                 overridePhysicalCameraSizes.get(j);
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index a169fee..22e2424 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -100,7 +100,46 @@
                     continue;
                 }
                 openDevice(mCameraIds[i]);
-                jpegExifTestByCamera();
+                Size maxJpegSize = mOrderedStillSizes.get(0);
+                stillExifTestByCamera(ImageFormat.JPEG, maxJpegSize);
+            } finally {
+                closeDevice();
+                closeImageReader();
+            }
+        }
+    }
+
+    /**
+     * Test HEIC capture exif fields for each camera.
+     */
+    @Test
+    public void testHeicExif() throws Exception {
+        for (int i = 0; i < mCameraIds.length; i++) {
+            try {
+                Log.i(TAG, "Testing HEIC exif for Camera " + mCameraIds[i]);
+                if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
+                if (!mAllStaticInfo.get(mCameraIds[i]).isHeicSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support HEIC, skipping");
+                    continue;
+                }
+
+                openDevice(mCameraIds[i]);
+
+                // Test maximum Heic size capture
+                List<Size> orderedHeicSizes = CameraTestUtils.getSupportedHeicSizes(
+                        mCameraIds[i], mCameraManager, null/*bound*/);
+                Size maxHeicSize = orderedHeicSizes.get(0);
+                stillExifTestByCamera(ImageFormat.HEIC, maxHeicSize);
+
+                // Test preview size Heic capture
+                Size previewSize = mOrderedPreviewSizes.get(0);
+                stillExifTestByCamera(ImageFormat.HEIC, previewSize);
+
             } finally {
                 closeDevice();
                 closeImageReader();
@@ -318,7 +357,7 @@
      * Test all combination of available preview sizes and still sizes.
      * <p>
      * For each still capture, Only the jpeg buffer is validated, capture
-     * result validation is covered by {@link #jpegExifTestByCamera} test.
+     * result validation is covered by {@link #stillExifTestByCamera} test.
      * </p>
      */
     @Test(timeout=60*60*1000) // timeout = 60 mins for long running tests
@@ -585,7 +624,7 @@
 
         // Set the max number of images to number of focal lengths supported
         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
-                maxStillSz, resultListener, focalLengths.length, imageListener);
+                maxStillSz, resultListener, focalLengths.length, imageListener, false /*isHeic*/);
 
         for(float focalLength : focalLengths) {
 
@@ -613,7 +652,7 @@
 
             validateJpegCapture(image, maxStillSz);
             verifyJpegKeys(image, result, maxStillSz, thumbnailSize, exifTestData,
-                    mStaticInfo, mCollector, mDebugFileNameBase);
+                    mStaticInfo, mCollector, mDebugFileNameBase, ImageFormat.JPEG);
         }
     }
 
@@ -633,7 +672,7 @@
         CaptureRequest.Builder stillRequest =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
-                maxStillSz, resultListener, imageListener);
+                maxStillSz, resultListener, imageListener, false /*isHeic*/);
 
         // make sure preview is actually running
         waitForNumResults(resultListener, NUM_FRAMES_WAITED);
@@ -719,7 +758,7 @@
             stillRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
         }
         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
-                maxStillSz, resultListener, imageListener);
+                maxStillSz, resultListener, imageListener, false /*isHeic*/);
 
         // Set AE mode to ON_AUTO_FLASH if flash is available.
         if (mStaticInfo.hasFlash()) {
@@ -930,7 +969,7 @@
                 CaptureRequest.Builder stillRequest =
                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, previewSz,
-                        stillSz, resultListener, imageListener);
+                        stillSz, resultListener, imageListener, false /*isHeic*/);
                 mSession.capture(stillRequest.build(), resultListener, mHandler);
                 Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ?
                         RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS);
@@ -1049,7 +1088,7 @@
             CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest,
                     NUM_RESULTS_WAIT_TIMEOUT);
             Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
-            basicValidateJpegImage(jpegImage, maxStillSz);
+            basicValidateBlobImage(jpegImage, maxStillSz, ImageFormat.JPEG);
             Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
             validateRaw16Image(rawImage, size);
             verifyRawCaptureResult(multiRequest, result);
@@ -1188,17 +1227,19 @@
     }
 
     /**
-     * Issue a Jpeg capture and validate the exif information.
+     * Issue a still capture and validate the exif information.
      * <p>
      * TODO: Differentiate full and limited device, some of the checks rely on
      * per frame control and synchronization, most of them don't.
      * </p>
      */
-    private void jpegExifTestByCamera() throws Exception {
+    private void stillExifTestByCamera(int format, Size stillSize) throws Exception {
+        assertTrue(format == ImageFormat.JPEG || format == ImageFormat.HEIC);
+        boolean isHeic = (format == ImageFormat.HEIC);
+
         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
-        Size maxStillSz = mOrderedStillSizes.get(0);
         if (VERBOSE) {
-            Log.v(TAG, "Testing JPEG exif with jpeg size " + maxStillSz.toString()
+            Log.v(TAG, "Testing exif with size " + stillSize.toString()
                     + ", preview size " + maxPreviewSz);
         }
 
@@ -1209,8 +1250,8 @@
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
-        prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, maxStillSz,
-                resultListener, imageListener);
+        prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, stillSize,
+                resultListener, imageListener, isHeic);
 
         // Set the jpeg keys, then issue a capture
         Size[] thumbnailSizes = mStaticInfo.getAvailableThumbnailSizesChecked();
@@ -1223,15 +1264,15 @@
         for (int i = 0; i < EXIF_TEST_DATA.length; i++) {
             setJpegKeys(stillBuilder, EXIF_TEST_DATA[i], testThumbnailSizes[i], mCollector);
 
-            // Capture a jpeg image.
+            // Capture a jpeg/heic image.
             CaptureRequest request = stillBuilder.build();
             mSession.capture(request, resultListener, mHandler);
             CaptureResult stillResult =
                     resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
 
-            verifyJpegKeys(image, stillResult, maxStillSz, testThumbnailSizes[i], EXIF_TEST_DATA[i],
-                    mStaticInfo, mCollector, mDebugFileNameBase);
+            verifyJpegKeys(image, stillResult, stillSize, testThumbnailSizes[i], EXIF_TEST_DATA[i],
+                    mStaticInfo, mCollector, mDebugFileNameBase, format);
 
             // Free image resources
             image.close();
@@ -1292,7 +1333,7 @@
         // Set the max number of images to be same as the burst count, as the verification
         // could be much slower than producing rate, and we don't want to starve producer.
         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
-                maxStillSz, resultListener, numSteps, imageListener);
+                maxStillSz, resultListener, numSteps, imageListener, false /*isHeic*/);
 
         for (int i = 0; i <= numSteps; i++) {
             int exposureCompensation = i * stepsPerEv + compensationRange.getLower();
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index 8c245bd..7a9ae93 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -285,9 +285,10 @@
     protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest,
             CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz,
             CaptureCallback resultListener,
-            ImageReader.OnImageAvailableListener imageListener) throws Exception {
+            ImageReader.OnImageAvailableListener imageListener, boolean isHeic) throws Exception {
         prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz,
-                ImageFormat.JPEG, resultListener, MAX_READER_IMAGES, imageListener);
+                isHeic ? ImageFormat.HEIC : ImageFormat.JPEG, resultListener, MAX_READER_IMAGES,
+                imageListener);
     }
 
     /**
@@ -304,9 +305,9 @@
     protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest,
             CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz,
             CaptureCallback resultListener, int maxNumImages,
-            ImageReader.OnImageAvailableListener imageListener) throws Exception {
+            ImageReader.OnImageAvailableListener imageListener, boolean isHeic) throws Exception {
         prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz,
-                ImageFormat.JPEG, resultListener, maxNumImages, imageListener);
+                isHeic ? ImageFormat.HEIC : ImageFormat.JPEG, resultListener, maxNumImages, imageListener);
     }
 
     /**
@@ -573,11 +574,13 @@
      * @param resultListener Capture result listener
      * @param maxNumImages The max number of images set to the image reader
      * @param imageListeners The single capture capture image listeners
+     * @param isHeic HEIC still capture if true, JPEG still capture if false
      */
     protected ImageReader[] prepareStillCaptureAndStartPreview(
             CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest,
             Size previewSz, Size[] captureSizes, int[] formats, CaptureCallback resultListener,
-            int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners)
+            int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners,
+            boolean isHeic)
             throws Exception {
 
         if ((captureSizes == null) || (formats == null) || (imageListeners == null) &&
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index 4fd4b39..883d86b 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -1035,11 +1035,12 @@
 
         ByteBuffer buffer = null;
         // JPEG doesn't have pixelstride and rowstride, treat it as 1D buffer.
-        // Same goes for DEPTH_POINT_CLOUD and DEPTH_JPEG
+        // Same goes for DEPTH_POINT_CLOUD, RAW_PRIVATE, DEPTH_JPEG, and HEIC
         if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD ||
-                format == ImageFormat.RAW_PRIVATE || format == ImageFormat.DEPTH_JPEG) {
+                format == ImageFormat.RAW_PRIVATE || format == ImageFormat.DEPTH_JPEG ||
+                format == ImageFormat.HEIC) {
             buffer = planes[0].getBuffer();
-            assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
+            assertNotNull("Fail to get jpeg/depth/heic ByteBuffer", buffer);
             data = new byte[buffer.remaining()];
             buffer.get(data);
             buffer.rewind();
@@ -1122,6 +1123,7 @@
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.DEPTH_JPEG:
             case ImageFormat.Y8:
+            case ImageFormat.HEIC:
                 assertEquals("JPEG/RAW/depth/Y8 Images should have one plane", 1, planes.length);
                 break;
             default:
@@ -1364,6 +1366,11 @@
         return getSortedSizesForFormat(cameraId, cameraManager, ImageFormat.JPEG, bound);
     }
 
+    static public List<Size> getSupportedHeicSizes(String cameraId,
+            CameraManager cameraManager, Size bound) throws CameraAccessException {
+        return getSortedSizesForFormat(cameraId, cameraManager, ImageFormat.HEIC, bound);
+    }
+
     static public Size getMinPreviewSize(String cameraId, CameraManager cameraManager)
             throws CameraAccessException {
         List<Size> sizes = getSupportedPreviewSizes(cameraId, cameraManager, null);
@@ -1551,6 +1558,9 @@
             case ImageFormat.Y8:
                 validateY8Data(data, width, height, format, image.getTimestamp(), filePath);
                 break;
+            case ImageFormat.HEIC:
+                validateHeicData(data, width, height, filePath);
+                break;
             default:
                 throw new UnsupportedOperationException("Unsupported format for validation: "
                         + format);
@@ -1733,6 +1743,26 @@
 
     }
 
+    private static void validateHeicData(byte[] heicData, int width, int height, String filePath) {
+        BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
+        // DecodeBound mode: only parse the frame header to get width/height.
+        // it doesn't decode the pixel.
+        bmpOptions.inJustDecodeBounds = true;
+        BitmapFactory.decodeByteArray(heicData, 0, heicData.length, bmpOptions);
+        assertEquals(width, bmpOptions.outWidth);
+        assertEquals(height, bmpOptions.outHeight);
+
+        // Pixel decoding mode: decode whole image. check if the image data
+        // is decodable here.
+        assertNotNull("Decoding heic failed",
+                BitmapFactory.decodeByteArray(heicData, 0, heicData.length));
+        if (DEBUG && filePath != null) {
+            String fileName =
+                    filePath + "/" + width + "x" + height + ".heic";
+            dumpFile(fileName, heicData);
+        }
+    }
+
     public static <T> T getValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
         if (result == null) {
             throw new IllegalArgumentException("Result must not be null");
@@ -2047,49 +2077,54 @@
      * continue the test if the jpeg image captured has some serious failures.
      * </p>
      *
-     * @param image The captured jpeg image
-     * @param expectedSize Expected capture jpeg size
+     * @param image The captured JPEG/HEIC image
+     * @param expectedSize Expected capture JEPG/HEIC size
+     * @param format JPEG/HEIC image format
      */
-    public static void basicValidateJpegImage(Image image, Size expectedSize) {
+    public static void basicValidateBlobImage(Image image, Size expectedSize, int format) {
         Size imageSz = new Size(image.getWidth(), image.getHeight());
         assertTrue(
                 String.format("Image size doesn't match (expected %s, actual %s) ",
                         expectedSize.toString(), imageSz.toString()), expectedSize.equals(imageSz));
-        assertEquals("Image format should be JPEG", ImageFormat.JPEG, image.getFormat());
+        assertEquals("Image format should be " + ((format == ImageFormat.HEIC) ? "HEIC" : "JPEG"),
+                format, image.getFormat());
         assertNotNull("Image plane shouldn't be null", image.getPlanes());
         assertEquals("Image plane number should be 1", 1, image.getPlanes().length);
 
-        // Jpeg decoding validate was done in ImageReaderTest, no need to duplicate the test here.
+        // Jpeg/Heic decoding validate was done in ImageReaderTest,
+        // no need to duplicate the test here.
     }
 
     /**
-     * Verify the JPEG EXIF and JPEG related keys in a capture result are expected.
+     * Verify the EXIF and JPEG related keys in a capture result are expected.
      * - Capture request get values are same as were set.
      * - capture result's exif data is the same as was set by
      *   the capture request.
      * - new tags in the result set by the camera service are
      *   present and semantically correct.
      *
-     * @param image The output JPEG image to verify.
+     * @param image The output JPEG/HEIC image to verify.
      * @param captureResult The capture result to verify.
-     * @param expectedSize The expected JPEG size.
+     * @param expectedSize The expected JPEG/HEIC size.
      * @param expectedThumbnailSize The expected thumbnail size.
      * @param expectedExifData The expected EXIF data
      * @param staticInfo The static metadata for the camera device.
-     * @param jpegFilename The filename to dump the jpeg to.
+     * @param blobFilename The filename to dump the jpeg/heic to.
      * @param collector The camera error collector to collect errors.
+     * @param format JPEG/HEIC format
      */
     public static void verifyJpegKeys(Image image, CaptureResult captureResult, Size expectedSize,
             Size expectedThumbnailSize, ExifTestData expectedExifData, StaticMetadata staticInfo,
-            CameraErrorCollector collector, String debugFileNameBase) throws Exception {
+            CameraErrorCollector collector, String debugFileNameBase, int format) throws Exception {
 
-        basicValidateJpegImage(image, expectedSize);
+        basicValidateBlobImage(image, expectedSize, format);
 
-        byte[] jpegBuffer = getDataFromImage(image);
+        byte[] blobBuffer = getDataFromImage(image);
         // Have to dump into a file to be able to use ExifInterface
-        String jpegFilename = debugFileNameBase + "/verifyJpegKeys.jpeg";
-        dumpFile(jpegFilename, jpegBuffer);
-        ExifInterface exif = new ExifInterface(jpegFilename);
+        String filePostfix = (format == ImageFormat.HEIC ? ".heic" : ".jpeg");
+        String blobFilename = debugFileNameBase + "/verifyJpegKeys" + filePostfix;
+        dumpFile(blobFilename, blobBuffer);
+        ExifInterface exif = new ExifInterface(blobFilename);
 
         if (expectedThumbnailSize.equals(new Size(0,0))) {
             collector.expectTrue("Jpeg shouldn't have thumbnail when thumbnail size is (0, 0)",
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 15701f1..6af6be5 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -1347,6 +1347,16 @@
     }
 
     /**
+     * Get supported heic output sizes and do the check.
+     *
+     * @return Empty size array if heic output is not supported
+     */
+    public Size[] getHeicOutputSizesChecked() {
+        return getAvailableSizesForFormatChecked(ImageFormat.HEIC,
+                StreamDirection.Output);
+    }
+
+    /**
      * Used to determine the stream direction for various helpers that look up
      * format or size information.
      */
@@ -2361,6 +2371,14 @@
     }
 
     /**
+     * Check if HEIC format is supported
+     */
+    public boolean isHeicSupported() {
+        int[] formats = getAvailableFormats(StaticMetadata.StreamDirection.Output);
+        return CameraTestUtils.contains(formats, ImageFormat.HEIC);
+    }
+
+    /**
      * Check if the dynamic black level is supported.
      *
      * <p>
diff --git a/tests/contentcaptureservice/AndroidTest.xml b/tests/contentcaptureservice/AndroidTest.xml
index e974112..f8afb9a 100644
--- a/tests/contentcaptureservice/AndroidTest.xml
+++ b/tests/contentcaptureservice/AndroidTest.xml
@@ -15,7 +15,8 @@
 -->
 <configuration description="Config for ContentCapture CTS tests.">
   <option name="test-suite-tag" value="cts" />
-  <option name="config-descriptor:metadata" key="component" value="framework" />
+  <option name="config-descriptor:metadata" key="component" value="contentcapture" />
+  <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
   <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
 
   <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
@@ -23,7 +24,10 @@
     <option name="test-file-name" value="CtsContentCaptureServiceTestCases.apk" />
   </target_preparer>
 
-  <!--  TODO(b/122605818): add preparer for instant-apps tests  -->
+  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+    <option name="run-command" value="cmd content_capture set bind-instant-service-allowed true" />
+    <option name="teardown-command" value="cmd content_capture set bind-instant-service-allowed false" />
+  </target_preparer>
 
   <test class="com.android.tradefed.testtype.AndroidJUnitTest">
     <option name="package" value="android.contentcaptureservice.cts" />
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
index f8f8092..072c770 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
@@ -15,7 +15,7 @@
  */
 package android.contentcaptureservice.cts;
 
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import android.app.Activity;
 import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
index 96f94b4..afcc95e 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
@@ -16,19 +16,20 @@
 package android.contentcaptureservice.cts;
 
 import static android.contentcaptureservice.cts.Helper.GENERIC_TIMEOUT_MS;
+import static android.contentcaptureservice.cts.Helper.SYSTEM_SERVICE_NAME;
 import static android.contentcaptureservice.cts.Helper.resetService;
+import static android.contentcaptureservice.cts.Helper.sContext;
 import static android.contentcaptureservice.cts.Helper.setService;
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
 import static android.provider.Settings.Secure.CONTENT_CAPTURE_ENABLED;
 
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
 import android.app.Application;
-import android.content.Context;
 import android.content.Intent;
 import android.contentcaptureservice.cts.CtsContentCaptureService.ServiceWatcher;
 import android.contentcaptureservice.cts.common.ActivitiesWatcher;
 import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
 import android.contentcaptureservice.cts.common.Visitor;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
@@ -42,7 +43,9 @@
 import com.android.compatibility.common.util.SettingsUtils;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
@@ -54,21 +57,37 @@
 public abstract class AbstractContentCaptureIntegrationTest
         <A extends AbstractContentCaptureActivity> {
 
-    private final String mTag = getClass().getSimpleName();
+    private static final String TAG = AbstractContentCaptureIntegrationTest.class.getSimpleName();
 
-    protected static final Context sContext = InstrumentationRegistry.getTargetContext();
+    private final String mTag = getClass().getSimpleName();
 
     protected ActivitiesWatcher mActivitiesWatcher;
 
     private final Class<A> mActivityClass;
 
     private final RequiredServiceRule mRequiredServiceRule =
-            new RequiredServiceRule("content_capture");
+            new RequiredServiceRule(SYSTEM_SERVICE_NAME);
 
     private final ContentCaptureLoggingTestRule mLoggingRule = new ContentCaptureLoggingTestRule();
 
+
+    /**
+     * Watcher set on {@link #enableService()} and used to wait until it's gone after the test
+     * finishes.
+     */
+    private ServiceWatcher mServiceWatcher;
+
     protected final SafeCleanerRule mSafeCleanerRule = new SafeCleanerRule()
             .setDumper(mLoggingRule)
+            .run(() -> {
+                Log.v(mTag, "@SafeCleaner: resetDefaultService()");
+                resetService();
+
+                if (mServiceWatcher != null) {
+                    mServiceWatcher.waitOnDestroy();
+                }
+
+            })
             .add(() -> {
                 return CtsContentCaptureService.getExceptions();
             });
@@ -93,16 +112,22 @@
             // Finally, let subclasses set their ActivityTestRule
             .around(getActivityTestRule());
 
-    /**
-     * Watcher set on {@link #enableService()} and used to wait until it's gone after the test
-     * finishes.
-     */
-    private ServiceWatcher mServiceWatcher;
-
     protected AbstractContentCaptureIntegrationTest(@NonNull Class<A> activityClass) {
         mActivityClass = activityClass;
     }
 
+    @BeforeClass
+    public static void disableDefaultService() {
+        Log.v(TAG, "@BeforeClass: disableDefaultService()");
+        Helper.setDefaultServiceEnabled(false);
+    }
+
+    @AfterClass
+    public static void enableDefaultService() {
+        Log.v(TAG, "@AfterClass: enableDefaultService()");
+        Helper.setDefaultServiceEnabled(true);
+    }
+
     @Before
     public void prepareDevice() throws Exception {
         Log.v(mTag, "@Before: prepareDevice()");
@@ -140,18 +165,6 @@
         }
     }
 
-    // TODO(b/123539404): this method should be called from the SafeCleaner, but we'll need to
-    // add a run() method that takes an object that can throw an exception
-    @After
-    public void restoreDefaultService() throws InterruptedException {
-        Log.v(mTag, "@After: restoreDefaultService()");
-        resetService();
-
-        if (mServiceWatcher != null) {
-            mServiceWatcher.waitOnDestroy();
-        }
-    }
-
     @Nullable
     public static void setFeatureEnabled(@Nullable String enabled) {
         if (enabled == null) {
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
index b74b22c..e3792ee 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
@@ -279,8 +279,18 @@
         assertThat(events).hasSize(minimumSize + 1);
         final ContentCaptureEvent batchDisappearEvent = events.get(minimumSize);
 
-        final List<AutofillId> actualIds = batchDisappearEvent.getIds();
-        assertThat(actualIds).containsExactly((Object[]) expectedIds);
+        if (expectedIds.length == 1) {
+            assertWithMessage("Should have just one deleted id on %s", batchDisappearEvent)
+                    .that(batchDisappearEvent.getIds()).isNull();
+            assertWithMessage("wrong deleted id on %s", batchDisappearEvent)
+                    .that(batchDisappearEvent.getId()).isEqualTo(expectedIds[0]);
+        } else {
+            assertWithMessage("Should not have individual deleted id on %s", batchDisappearEvent)
+                    .that(batchDisappearEvent.getId()).isNull();
+            final List<AutofillId> actualIds = batchDisappearEvent.getIds();
+            assertWithMessage("wrong deleteds id on %s", batchDisappearEvent)
+                    .that(actualIds).containsExactly((Object[]) expectedIds);
+        }
     }
 
     /**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
index 5a78cb6..abb0e7e 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
@@ -25,6 +25,7 @@
 import android.content.ComponentName;
 import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
 import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 
@@ -33,6 +34,7 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class BlankActivityTest extends AbstractContentCaptureIntegrationTest<BlankActivity> {
 
     private static final String TAG = BlankActivityTest.class.getSimpleName();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
index d99dfec..28dc2e7 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
 import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 
@@ -60,6 +61,7 @@
         activity.assertDefaultEvents(session);
     }
 
+    @AppModeFull(reason = "testSimpleSessionLifecycle() is enough")
     @Test
     public void testSimpleSessionLifecycle_noAnimation() throws Exception {
         final CtsContentCaptureService service = enableService();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CanaryTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CanaryTest.java
new file mode 100644
index 0000000..56839e2
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CanaryTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Helper.RESOURCE_STRING_SERVICE_NAME;
+import static android.contentcaptureservice.cts.Helper.SYSTEM_SERVICE_NAME;
+import static android.contentcaptureservice.cts.Helper.getInternalString;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.provider.DeviceConfig;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureManager;
+
+import com.android.compatibility.common.util.RequiredServiceRule;
+
+import org.junit.Test;
+
+/**
+ * No-op test used to make sure the other tests are not passing because the feature is disabled.
+ */
+public class CanaryTest {
+
+    private static final String TAG = CanaryTest.class.getSimpleName();
+
+    @Test
+    public void logHasService() {
+        final boolean hasService = RequiredServiceRule.hasService(SYSTEM_SERVICE_NAME);
+        Log.d(TAG, "has " + SYSTEM_SERVICE_NAME + ": " + hasService);
+        assumeTrue("device doesn't have service " + SYSTEM_SERVICE_NAME, hasService);
+    }
+
+    @Test
+    public void assertHasService() {
+        final String serviceName = getInternalString(RESOURCE_STRING_SERVICE_NAME);
+        final String enableSettings = DeviceConfig.getProperty(
+                DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+        final boolean hasService = RequiredServiceRule.hasService(SYSTEM_SERVICE_NAME);
+        Log.d(TAG, "Service resource: '" + serviceName + "' Settings: '" + enableSettings
+                + "' Has '" + SYSTEM_SERVICE_NAME + "': " + hasService);
+
+        // We're only asserting when the OEM defines a service
+        assumeTrue("service resource (" + serviceName + ")is not defined",
+                !TextUtils.isEmpty(serviceName));
+        assertWithMessage("Should be enabled when resource '%s' is not empty (settings='%s')",
+                serviceName, enableSettings).that(hasService).isTrue();
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
index 3af2c65..25928cd 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
@@ -29,6 +29,7 @@
 import static android.contentcaptureservice.cts.Assertions.assertViewsDisappeared;
 import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
 import static android.contentcaptureservice.cts.Helper.newImportantView;
+import static android.contentcaptureservice.cts.Helper.sContext;
 import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
 import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.RESUMED;
 
@@ -43,6 +44,8 @@
 import android.contentcaptureservice.cts.common.ActivityLauncher;
 import android.net.Uri;
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.DeviceConfig;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 import android.view.View;
@@ -56,16 +59,17 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class ChildlessActivityTest
         extends AbstractContentCaptureIntegrationTest<ChildlessActivity> {
 
@@ -106,7 +110,6 @@
         activity.assertDefaultEvents(session);
     }
 
-    @Ignore("not implemented yet, pending on b/123658889")
     @Test
     public void testGetContentCapture_disabledWhenNoService() throws Exception {
 
@@ -920,6 +923,28 @@
      * - etc
      */
 
+    private enum DisabledReason {
+        BY_API,
+        BY_SETTINGS,
+        BY_DEVICE_CONFIG
+    }
+
+    private void setFeatureEnabled(@NonNull ContentCaptureManager mgr,
+            @NonNull DisabledReason reason, boolean enabled) {
+        switch (reason) {
+            case BY_API:
+                mgr.setContentCaptureFeatureEnabled(enabled);
+                break;
+            case BY_SETTINGS:
+                setFeatureEnabled(Boolean.toString(enabled));
+                break;
+            case BY_DEVICE_CONFIG:
+                setFeatureEnabledByDeviceConfig(Boolean.toString(enabled));
+                break;
+            default:
+                throw new IllegalArgumentException("invalid reason: " + reason);
+        }
+    }
     @Test
     public void testIsContentCaptureFeatureEnabled_notService() throws Exception {
         final ContentCaptureManager mgr = getContentCaptureManagerHack();
@@ -928,21 +953,18 @@
 
     @Test
     public void testSetContentCaptureFeatureEnabled_disabledBySettings() throws Exception {
-        setContentCaptureFeatureEnabledTest_disabled(/* bySettings= */ true);
+        setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_SETTINGS);
     }
 
-    private void setContentCaptureFeatureEnabledTest_disabled(boolean bySettings) throws Exception {
+    private void setContentCaptureFeatureEnabledTest_disabled(@NonNull DisabledReason reason)
+            throws Exception {
         final ContentCaptureManager mgr = getContentCaptureManagerHack();
 
         final CtsContentCaptureService service = enableService();
         assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
         final DisconnectListener disconnectedListener = service.setOnDisconnectListener();
 
-        if (bySettings) {
-            setFeatureEnabled("false");
-        } else {
-            mgr.setContentCaptureFeatureEnabled(false);
-        }
+        setFeatureEnabled(mgr, reason, /* enabled= */ false);
 
         disconnectedListener.waitForOnDisconnected();
         assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse();
@@ -961,22 +983,18 @@
     @Test
     public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledBySettings()
             throws Exception {
-        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(/* bySettings= */ true);
+        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_SETTINGS);
     }
 
-    private void setContentCaptureFeatureEnabledTest_disabledThenReEnabled(boolean bySettings)
-            throws Exception {
+    private void setContentCaptureFeatureEnabledTest_disabledThenReEnabled(
+            @NonNull DisabledReason reason) throws Exception {
         final ContentCaptureManager mgr = getContentCaptureManagerHack();
 
         final CtsContentCaptureService service1 = enableService();
         assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
         final DisconnectListener disconnectedListener = service1.setOnDisconnectListener();
 
-        if (bySettings) {
-            setFeatureEnabled("false");
-        } else {
-            mgr.setContentCaptureFeatureEnabled(false);
-        }
+        setFeatureEnabled(mgr, reason, /* enabled= */ false);
         disconnectedListener.waitForOnDisconnected();
 
         assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse();
@@ -991,11 +1009,7 @@
 
         // Re-enable feature
         final ServiceWatcher reconnectionWatcher = CtsContentCaptureService.setServiceWatcher();
-        if (bySettings) {
-            setFeatureEnabled("true");
-        } else {
-            mgr.setContentCaptureFeatureEnabled(true);
-        }
+        setFeatureEnabled(mgr, reason, /* enabled= */ true);
         final CtsContentCaptureService service2 = reconnectionWatcher.waitOnCreate();
         assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
 
@@ -1021,13 +1035,30 @@
 
     @Test
     public void testSetContentCaptureFeatureEnabled_disabledByApi() throws Exception {
-        setContentCaptureFeatureEnabledTest_disabled(/* bySettings= */ false);
+        setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_API);
     }
 
     @Test
     public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByApi()
             throws Exception {
-        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(/* bySettings= */ false);
+        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_API);
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledByDeviceConfig() throws Exception {
+        setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_DEVICE_CONFIG);
+        // Reset service, otherwise it will reconnect when the deviceConfig value is reset
+        // on cleanup, which will cause the test to fail
+        Helper.resetService();
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByDeviceConfig()
+            throws Exception {
+        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_DEVICE_CONFIG);
+        // Reset service, otherwise it will reconnect when the deviceConfig value is reset
+        // on cleanup, which will cause the test to fail
+        Helper.resetService();
     }
 
     // TODO(b/123406031): add tests that mix feature_enabled with user_restriction_enabled (and
@@ -1084,4 +1115,34 @@
 
         return mgr;
     }
+
+    // TODO(b/124006095): should use a @Rule instead
+    private String mEnabledBefore;
+    @Before
+    public void saveDeviceConfig() {
+        mEnabledBefore = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+        Log.d(TAG, "@Before saveDeviceConfig(): " + mEnabledBefore);
+
+        setFeatureEnabledByDeviceConfig(null);
+
+    }
+    @After
+    // TODO(b/124006095): should use a @Rule instead
+    public void restoreDeviceConfig() {
+        Log.d(TAG, "@After restoreDeviceConfig(): " + mEnabledBefore);
+        setFeatureEnabledByDeviceConfig(mEnabledBefore);
+
+    }
+    // TODO(b/124006095): should use a DeviceConfigUtils instead
+    private void setFeatureEnabledByDeviceConfig(@Nullable String value) {
+        Log.d(TAG, "setFeatureEnabledByDeviceConfig(): " + value);
+
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED,
+                value, /* makeDefault= */ false);
+
+        android.os.SystemClock.sleep(1000); // Wait a little bit since we're not using a listener
+    }
+
 }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java
index c7b831a..f829c60 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java
@@ -18,7 +18,8 @@
 
 import static android.contentcaptureservice.cts.Helper.MY_PACKAGE;
 import static android.contentcaptureservice.cts.Helper.TAG;
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import android.util.Log;
 
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
index e869fc1..04213ba 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
@@ -58,11 +58,6 @@
 
     private static ServiceWatcher sServiceWatcher;
 
-    // TODO(b/123421324): reuse with allSessions
-    /** Used by {@link #getOnlyFinishedSession()}. */
-    private static ContentCaptureSessionId sFirstSessionId;
-
-
     private final int mId = ++sIdCounter;
 
     private static final ArrayList<Throwable> sExceptions = new ArrayList<>();
@@ -118,7 +113,6 @@
 
 
     public static void resetStaticState() {
-        sFirstSessionId = null;
         sExceptions.clear();
         // TODO(b/123540602): should probably set sInstance to null as well, but first we would need
         // to make sure each test unbinds the service.
@@ -202,11 +196,8 @@
     public void onCreateContentCaptureSession(ContentCaptureContext context,
             ContentCaptureSessionId sessionId) {
         Log.i(TAG, "onCreateContentCaptureSession(id=" + mId + ", ctx=" + context
-                + ", session=" + sessionId + ", firstId=" + sFirstSessionId + ")");
+                + ", session=" + sessionId);
         mAllSessions.add(sessionId);
-        if (sFirstSessionId == null) {
-            sFirstSessionId = sessionId;
-        }
 
         safeRun(() -> {
             final Session session = mOpenSessions.get(sessionId);
@@ -289,9 +280,11 @@
      */
     @NonNull
     public Session getOnlyFinishedSession() throws InterruptedException {
-        // TODO(b/123421324): add some assertions to make sure There Can Be Only One!
-        assertWithMessage("No session yet").that(sFirstSessionId).isNotNull();
-        return getFinishedSession(sFirstSessionId);
+        final ArrayList<ContentCaptureSessionId> allSessions = mAllSessions;
+        assertWithMessage("Wrong number of sessions").that(allSessions).hasSize(1);
+        final ContentCaptureSessionId id = allSessions.get(0);
+        Log.d(TAG, "getOnlyFinishedSession(): id=" + id);
+        return getFinishedSession(id);
     }
 
     /**
@@ -319,7 +312,6 @@
         super.dump(fd, pw, args);
 
         pw.print("sServiceWatcher: "); pw.println(sServiceWatcher);
-        pw.print("sFirstSessionId: "); pw.println(sFirstSessionId);
         pw.print("sExceptions: "); pw.println(sExceptions);
         pw.print("sIdCounter: "); pw.println(sIdCounter);
         pw.print("mId: "); pw.println(mId);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
index 92b4f53..33cd31f 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
@@ -101,13 +101,16 @@
     @NonNull
     private List<ContentCaptureEvent> assertJustInitialViewsAppeared(@NonNull Session session,
             int additionalEvents) {
-        final List<ContentCaptureEvent> events = session.getEvents();
-        Log.v(TAG, "events(" + events.size() + "): " + events);
-        assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
-
         final View grandpa1 = (View) mCustomView.getParent();
         final View grandpa2 = (View) grandpa1.getParent();
         final View decorView = getDecorView();
+        Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId()
+                + ", grandpa2=" + grandpa2.getAutofillId() + ", decor="
+                + decorView.getAutofillId());
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+        assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
 
         // Assert just the relevant events
         assertViewHierarchyStarted(events, 0);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
index 0218b4a..0ab1425 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
@@ -15,7 +15,11 @@
  */
 package android.contentcaptureservice.cts;
 
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewHierarchyFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewHierarchyStarted;
 import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewDisappeared;
@@ -31,8 +35,10 @@
 import android.contentcaptureservice.cts.common.DoubleVisitor;
 import android.os.Handler;
 import android.os.Looper;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
+import android.view.View;
 import android.view.ViewStructure;
 import android.view.autofill.AutofillId;
 import android.view.contentcapture.ContentCaptureEvent;
@@ -40,13 +46,13 @@
 
 import androidx.annotation.NonNull;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class CustomViewActivityTest extends
         AbstractContentCaptureIntegrationTest<CustomViewActivity> {
 
@@ -89,7 +95,6 @@
      * the session notification methods instead - this is wrong because the main view will be
      * notified last, but we cannot prevent the apps from doing so...
      */
-    @Ignore("current broken, will be fixed by b/123777277")
     @Test
     public void testVirtualView_wrongWay() throws Exception {
         final CtsContentCaptureService service = enableService();
@@ -123,24 +128,36 @@
 
         assertRightActivity(session, session.id, activity);
 
-
-        final int additionalEvents = 3;
-        final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session,
-                additionalEvents);
-
+        final View grandpa1 = (View) activity.mCustomView.getParent();
+        final View grandpa2 = (View) grandpa1.getParent();
+        final View decorView = activity.getDecorView();
         final AutofillId customViewId = activity.mCustomView.getAutofillId();
+        Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId()
+                + ", grandpa2=" + grandpa2.getAutofillId() + ", decor="
+                + decorView.getAutofillId() + "customView=" + customViewId);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+        final int additionalEvents = 2;
+
+        assertThat(events.size()).isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents);
+
+        // Assert just the relevant events
+        assertViewHierarchyStarted(events, 0);
+        assertDecorViewAppeared(events, 1, decorView);
+        assertViewAppeared(events, 2, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(events, 3, grandpa1, grandpa2.getAutofillId());
+
         final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
-
-        final int i = CustomViewActivity.MIN_EVENTS;
-
-        assertVirtualViewAppeared(events, i, mainSession, customViewId, 1, "child");
-        assertVirtualViewDisappeared(events, i + 1, customViewId, mainSession, 1);
+        assertVirtualViewAppeared(events, 4, mainSession, customViewId, 1, "child");
+        assertVirtualViewDisappeared(events, 5, customViewId, mainSession, 1);
 
         // This is the "wrong" part - the parent is notified last
-        assertViewWithUnknownParentAppeared(events, i + 2, session.id, activity.mCustomView);
+        assertViewWithUnknownParentAppeared(events, 6, session.id, activity.mCustomView);
+
+        assertViewHierarchyFinished(events, 7);
 
         activity.assertInitialViewsDisappeared(events, additionalEvents);
-        // TODO(b/122315042): assert views disappeared
     }
 
     /**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
index 9784213..3b78e21 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
@@ -15,11 +15,13 @@
  */
 package android.contentcaptureservice.cts;
 
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Resources;
 import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
@@ -33,7 +35,7 @@
 /**
  * Helper for common funcionalities.
  */
-final class Helper {
+public final class Helper {
 
     public static final String TAG = "ContentCaptureTest";
 
@@ -43,6 +45,12 @@
 
     public static final long MY_EPOCH = SystemClock.uptimeMillis();
 
+    public static final String SYSTEM_SERVICE_NAME = "content_capture";
+
+    public static final String RESOURCE_STRING_SERVICE_NAME = "config_defaultContentCaptureService";
+
+    public static final Context sContext = InstrumentationRegistry.getTargetContext();
+
     /**
      * Awaits for a latch to be counted down.
      */
@@ -74,6 +82,15 @@
     }
 
     /**
+     * Enables / disables the default service.
+     */
+    public static void setDefaultServiceEnabled(boolean enabled) {
+        Log.d(TAG, "setDefaultServiceEnabled(): " + enabled);
+        runShellCommand("cmd content_capture set default-service-enabled 0 %s",
+                Boolean.toString(enabled));
+    }
+
+    /**
      * Gets the component name for a given class.
      */
     public static ComponentName componentNameFor(@NonNull Class<?> clazz) {
@@ -90,6 +107,15 @@
         return child;
     }
 
+    /**
+     * Gets a string from the Android resources.
+     */
+    public static String getInternalString(@NonNull String id) {
+        final Resources resources = sContext.getResources();
+        final int stringId = resources.getIdentifier(id, "string", "android");
+        return resources.getString(stringId);
+    }
+
     private Helper() {
         throw new UnsupportedOperationException("contain static methods only");
     }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
index d78c329..926f63a 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
@@ -38,6 +38,7 @@
 import android.contentcaptureservice.cts.common.DoubleVisitor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 import android.view.View;
@@ -59,6 +60,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class LoginActivityTest extends AbstractContentCaptureIntegrationTest<LoginActivity> {
 
     private static final String TAG = LoginActivityTest.class.getSimpleName();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt
deleted file mode 100644
index 2cdbf75..0000000
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This package contains utilities that are not tied to Content Capture and might eventually move to
-a common CTS package.
\ No newline at end of file
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ShellHelper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ShellHelper.java
deleted file mode 100644
index a9b1481..0000000
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ShellHelper.java
+++ /dev/null
@@ -1,53 +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.
- */
-
-package android.contentcaptureservice.cts.common;
-
-import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-/**
- * Provides Shell-based utilities such as running a command.
- */
-public final class ShellHelper {
-
-    private static final String TAG = "ShellHelper";
-
-    /**
-     * Runs a Shell command, returning a trimmed response.
-     */
-    @NonNull
-    public static String runShellCommand(@NonNull String template, Object... args) {
-        final String command = String.format(template, args);
-        Log.d(TAG, "runShellCommand(): " + command);
-        try {
-            final String result = SystemUtil
-                    .runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
-            return TextUtils.isEmpty(result) ? "" : result.trim();
-        } catch (Exception e) {
-            throw new RuntimeException("Command '" + command + "' failed: ", e);
-        }
-    }
-
-    private ShellHelper() {
-        throw new UnsupportedOperationException("contain static methods only");
-    }
-}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureContextTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ContentCaptureContextTest.java
similarity index 98%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureContextTest.java
rename to tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ContentCaptureContextTest.java
index c19f0f7..ed1ffce 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureContextTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ContentCaptureContextTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.contentcaptureservice.cts;
+package android.contentcaptureservice.cts.unit;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,8 +34,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+@AppModeFull(reason = "unit test")
 @RunWith(JUnit4.class)
-@AppModeFull // Unit test
 public class ContentCaptureContextTest {
 
     private static final Uri URI = Uri.parse("file:/dev/null");
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/UserDataRemovalRequestTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/UserDataRemovalRequestTest.java
new file mode 100644
index 0000000..93a15ec
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/UserDataRemovalRequestTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.contentcaptureservice.cts.unit;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.net.Uri;
+import android.platform.test.annotations.AppModeFull;
+import android.view.contentcapture.UserDataRemovalRequest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@AppModeFull(reason = "unit test")
+@RunWith(MockitoJUnitRunner.class)
+public class UserDataRemovalRequestTest {
+
+    @Mock
+    private final Uri mUri = Uri.parse("content://com.example/");
+
+    private UserDataRemovalRequest.Builder mBuilder = new UserDataRemovalRequest.Builder();
+
+    @Test
+    public void testBuilder_addUri_invalid() {
+        assertThrows(NullPointerException.class, () -> mBuilder.addUri(null, false));
+    }
+
+    @Test
+    public void testBuilder_addUri_valid() {
+        assertThat(mBuilder.addUri(mUri, false)).isNotNull();
+        assertThat(mBuilder.addUri(Uri.parse("content://com.example2"), true)).isNotNull();
+    }
+
+    @Test
+    public void testBuilder_addUriAfterForEverything() {
+        assertThat(mBuilder.forEverything()).isNotNull();
+        assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
+    }
+
+    @Test
+    public void testBuilder_forEverythingAfterAddingUri() {
+        assertThat(mBuilder.addUri(mUri, false)).isNotNull();
+        assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
+    }
+
+    @Test
+    public void testBuild_invalid() {
+        assertThrows(IllegalStateException.class, () -> mBuilder.build());
+    }
+
+    @Test
+    public void testBuild_valid() {
+        assertThat(new UserDataRemovalRequest.Builder().forEverything().build())
+                .isNotNull();
+        assertThat(new UserDataRemovalRequest.Builder().addUri(mUri, false).build())
+                .isNotNull();
+    }
+
+    @Test
+    public void testNoMoreInteractionsAfterBuild() {
+        assertThat(mBuilder.forEverything().build()).isNotNull();
+
+        assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
+        assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
+        assertThrows(IllegalStateException.class, () -> mBuilder.build());
+
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ViewNodeTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ViewNodeTest.java
new file mode 100644
index 0000000..8d9cdeb
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ViewNodeTest.java
@@ -0,0 +1,415 @@
+/*
+ * 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.contentcaptureservice.cts.unit;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.os.Parcel;
+import android.platform.test.annotations.AppModeFull;
+import android.support.test.InstrumentationRegistry;
+import android.view.View;
+import android.view.ViewStructure.HtmlInfo;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.contentcapture.ViewNode;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import android.widget.FrameLayout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Locale;
+
+@AppModeFull(reason = "unit test")
+@RunWith(MockitoJUnitRunner.class)
+public class ViewNodeTest {
+
+    private final Context mContext = InstrumentationRegistry.getTargetContext();
+
+    @Mock
+    private HtmlInfo mHtmlInfoMock;
+
+    @Test
+    public void testAutofillIdMethods_orphanView() {
+        View view = new View(mContext);
+        AutofillId initialId = new AutofillId(42);
+        view.setAutofillId(initialId);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(initialId);
+        assertThat(node.getParentAutofillId()).isNull();
+
+        AutofillId newId = new AutofillId(108);
+        structure.setAutofillId(newId);
+        assertThat(node.getAutofillId()).isEqualTo(newId);
+        assertThat(node.getParentAutofillId()).isNull();
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testAutofillIdMethods_parentedView() {
+        FrameLayout parent = new FrameLayout(mContext);
+        AutofillId initialParentId = new AutofillId(48);
+        parent.setAutofillId(initialParentId);
+
+        View child = new View(mContext);
+        AutofillId initialChildId = new AutofillId(42);
+        child.setAutofillId(initialChildId);
+
+        parent.addView(child);
+
+        ViewStructureImpl structure = new ViewStructureImpl(child);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(initialChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newChildId = new AutofillId(108);
+        structure.setAutofillId(newChildId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newParentId = new AutofillId(15162342);
+        parent.setAutofillId(newParentId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testAutofillIdMethods_explicitIdsConstructor() {
+        AutofillId initialParentId = new AutofillId(42);
+        ViewStructureImpl structure = new ViewStructureImpl(initialParentId, 108, 666);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(initialParentId, 108, 666));
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newChildId = new AutofillId(108);
+        structure.setAutofillId(newChildId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testInvalidSetters() {
+        View view = new View(mContext);
+        AutofillId initialId = new AutofillId(42);
+        view.setAutofillId(initialId);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // sanity check
+
+        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null));
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null, 666));
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+        assertThrows(NullPointerException.class, () -> structure.setTextIdEntry(null));
+        assertThat(node.getTextIdEntry()).isNull();
+    }
+
+    @Test
+    public void testValidProperties_directly() {
+        ViewStructureImpl structure = newSimpleStructure();
+        assertSimpleStructure(structure);
+        assertSimpleNode(structure.getNode());
+    }
+
+    @Test
+    public void testValidProperties_throughParcel() {
+        ViewStructureImpl structure = newSimpleStructure();
+        final ViewNode node = structure.getNode();
+        assertSimpleNode(node); // sanity check
+
+        final ViewNode clone = cloneThroughParcel(node);
+        assertSimpleNode(clone);
+    }
+
+    @Test
+    public void testComplexText_directly() {
+        ViewStructureImpl structure = newStructureWithComplexText();
+        assertStructureWithComplexText(structure);
+        assertNodeWithComplexText(structure.getNode());
+    }
+
+    @Test
+    public void testComplexText_throughParcel() {
+        ViewStructureImpl structure = newStructureWithComplexText();
+        final ViewNode node = structure.getNode();
+        assertNodeWithComplexText(node); // sanity check
+
+        ViewNode clone = cloneThroughParcel(node);
+        assertNodeWithComplexText(clone);
+    }
+
+    @Test
+    public void testVisibility() {
+        // Visibility is a special case becase it use flag masks, so we want to make sure it works
+        // fine
+        View view = new View(mContext);
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        structure.setVisibility(View.VISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.GONE);
+        assertThat(node.getVisibility()).isEqualTo(View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+
+        structure.setVisibility(View.VISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.INVISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE);
+
+        structure.setVisibility(View.INVISIBLE | View.GONE);
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+
+
+        final int invalidValue = Math.max(Math.max(View.VISIBLE, View.INVISIBLE), View.GONE) * 2;
+        structure.setVisibility(View.VISIBLE);
+        structure.setVisibility(invalidValue); // should be ignored
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.GONE | invalidValue);
+        assertThat(node.getVisibility()).isEqualTo(View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+    }
+
+    /**
+     * Creates a {@link ViewStructureImpl} that can be asserted through
+     * {@link #assertSimpleNode(ViewNode)}.
+     */
+    private ViewStructureImpl newSimpleStructure() {
+        View view = new View(mContext);
+        view.setAutofillId(new AutofillId(42));
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+
+        // Basic properties
+        structure.setText("Text is set!");
+        structure.setClassName("Classy!");
+        structure.setContentDescription("Described I am!");
+        structure.setVisibility(View.INVISIBLE);
+
+        // Autofill properties
+        structure.setAutofillType(View.AUTOFILL_TYPE_TEXT);
+        structure.setAutofillHints(new String[] { "Auto", "Man" });
+        structure.setAutofillOptions(new String[] { "Maybe" });
+        structure.setAutofillValue(AutofillValue.forText("Malkovich"));
+
+        // Extra text properties
+        structure.setMinTextEms(6);
+        structure.setMaxTextLength(66);
+        structure.setMaxTextEms(666);
+        structure.setInputType(42);
+        structure.setTextIdEntry("TEXT, Y U NO ENTRY?");
+        structure.setLocaleList(new LocaleList(Locale.US, Locale.ENGLISH));
+
+        // Resource id
+        structure.setId(16, "package.name", "type.name", "entry.name");
+
+        // Dimensions
+        structure.setDimens(4, 8, 15, 16, 23, 42);
+
+        // Boolean properties
+        structure.setAssistBlocked(true);
+        structure.setEnabled(true);
+        structure.setClickable(true);
+        structure.setLongClickable(true);
+        structure.setContextClickable(true);
+        structure.setFocusable(true);
+        structure.setFocused(true);
+        structure.setAccessibilityFocused(true);
+        structure.setChecked(true);
+        structure.setActivated(true);
+        structure.setOpaque(true);
+
+        // Bundle
+        assertThat(structure.hasExtras()).isFalse();
+        final Bundle bundle = structure.getExtras();
+        assertThat(bundle).isNotNull();
+        bundle.putString("Marlon", "Bundle");
+        assertThat(structure.hasExtras()).isTrue();
+        return structure;
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewNode} that was created by
+     * {@link #newSimpleStructure()}.
+     */
+    private void assertSimpleNode(ViewNode node) {
+
+        // Basic properties
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(42));
+        assertThat(node.getParentAutofillId()).isNull();
+        assertThat(node.getText()).isEqualTo("Text is set!");
+        assertThat(node.getClassName()).isEqualTo("Classy!");
+        assertThat(node.getContentDescription().toString()).isEqualTo("Described I am!");
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+
+        // Autofill properties
+        assertThat(node.getAutofillType()).isEqualTo(View.AUTOFILL_TYPE_TEXT);
+        assertThat(node.getAutofillHints()).asList().containsExactly("Auto", "Man").inOrder();
+        assertThat(node.getAutofillOptions()).asList().containsExactly("Maybe").inOrder();
+        assertThat(node.getAutofillValue().getTextValue()).isEqualTo("Malkovich");
+
+        // Extra text properties
+        assertThat(node.getMinTextEms()).isEqualTo(6);
+        assertThat(node.getMaxTextLength()).isEqualTo(66);
+        assertThat(node.getMaxTextEms()).isEqualTo(666);
+        assertThat(node.getInputType()).isEqualTo(42);
+        assertThat(node.getTextIdEntry()).isEqualTo("TEXT, Y U NO ENTRY?");
+        assertThat(node.getLocaleList()).isEqualTo(new LocaleList(Locale.US, Locale.ENGLISH));
+
+        // Resource id
+        assertThat(node.getId()).isEqualTo(16);
+        assertThat(node.getIdPackage()).isEqualTo("package.name");
+        assertThat(node.getIdType()).isEqualTo("type.name");
+        assertThat(node.getIdEntry()).isEqualTo("entry.name");
+
+        // Dimensions
+        assertThat(node.getLeft()).isEqualTo(4);
+        assertThat(node.getTop()).isEqualTo(8);
+        assertThat(node.getScrollX()).isEqualTo(15);
+        assertThat(node.getScrollY()).isEqualTo(16);
+        assertThat(node.getWidth()).isEqualTo(23);
+        assertThat(node.getHeight()).isEqualTo(42);
+
+        // Boolean properties
+        assertThat(node.isAssistBlocked()).isTrue();
+        assertThat(node.isEnabled()).isTrue();
+        assertThat(node.isClickable()).isTrue();
+        assertThat(node.isLongClickable()).isTrue();
+        assertThat(node.isContextClickable()).isTrue();
+        assertThat(node.isFocusable()).isTrue();
+        assertThat(node.isFocused()).isTrue();
+        assertThat(node.isAccessibilityFocused()).isTrue();
+        assertThat(node.isChecked()).isTrue();
+        assertThat(node.isActivated()).isTrue();
+        assertThat(node.isOpaque()).isTrue();
+
+        // Bundle
+        final Bundle bundle = node.getExtras();
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.size()).isEqualTo(1);
+        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewStructureImpl} that was created by
+     * {@link #newSimpleStructure()}.
+     */
+    private void assertSimpleStructure(ViewStructureImpl structure) {
+        assertThat(structure.getAutofillId()).isEqualTo(new AutofillId(42));
+        assertThat(structure.getText()).isEqualTo("Text is set!");
+
+        // Bundle
+        final Bundle bundle = structure.getExtras();
+        assertThat(bundle.size()).isEqualTo(1);
+        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+    }
+
+    /**
+     * Creates a {@link ViewStructureImpl} with "complex" text properties (such as selection); it
+     * can be asserted through {@link #assertNodeWithComplexText(ViewNode)}.
+     */
+    private ViewStructureImpl newStructureWithComplexText() {
+        View view = new View(mContext);
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        structure.setText("IGNORE ME!");
+        structure.setText("Now we're talking!", 4, 8);
+        structure.setHint("Soylent Green is SPOILER ALERT");
+        structure.setTextStyle(15.0f, 16, 23, 42);
+        structure.setTextLines(new int[] {4,  8, 15} , new int[] {16, 23, 42});
+        return structure;
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewNode} that was created by
+     * {@link #newStructureWithComplexText()}.
+     */
+    private void assertNodeWithComplexText(ViewNode node) {
+        assertThat(node.getText()).isEqualTo("Now we're talking!");
+        assertThat(node.getTextSelectionStart()).isEqualTo(4);
+        assertThat(node.getTextSelectionEnd()).isEqualTo(8);
+        assertThat(node.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+        assertThat(node.getTextSize()).isWithin(1.0e-10f).of(15.0f);
+        assertThat(node.getTextColor()).isEqualTo(16);
+        assertThat(node.getTextBackgroundColor()).isEqualTo(23);
+        assertThat(node.getTextStyle()).isEqualTo(42);
+        assertThat(node.getTextLineCharOffsets()).asList().containsExactly(4, 8, 15).inOrder();
+        assertThat(node.getTextLineBaselines()).asList().containsExactly(16, 23, 42).inOrder();
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewStructureImpl} that was created by
+     * {@link #newStructureWithComplexText()}.
+     */
+    private void assertStructureWithComplexText(ViewStructureImpl structure) {
+        assertThat(structure.getText()).isEqualTo("Now we're talking!");
+        assertThat(structure.getTextSelectionStart()).isEqualTo(4);
+        assertThat(structure.getTextSelectionEnd()).isEqualTo(8);
+        assertThat(structure.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+    }
+
+    private ViewNode cloneThroughParcel(ViewNode node) {
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Write to parcel
+            parcel.setDataPosition(0); // Sanity / paranoid check
+            ViewNode.writeToParcel(parcel, node, 0);
+
+            // Read from parcel
+            parcel.setDataPosition(0);
+            ViewNode clone = ViewNode.readFromParcel(parcel);
+            assertThat(clone).isNotNull();
+            return clone;
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/tests/fragment/Android.bp b/tests/fragment/Android.bp
new file mode 100644
index 0000000..64a4486
--- /dev/null
+++ b/tests/fragment/Android.bp
@@ -0,0 +1,47 @@
+// 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.
+
+android_test {
+    name: "CtsFragmentTestCases",
+    defaults: ["cts_defaults"],
+
+    dex_preopt: {
+        enabled: false,
+    },
+
+    optimize: {
+        enabled: false,
+    },
+
+    static_libs: [
+        "android-support-test",
+        "mockito-target-minus-junit4",
+        "android-common",
+        "compatibility-device-util",
+        "ctstestrunner",
+    ],
+    libs: ["android.test.base.stubs"],
+
+    srcs: ["src/**/*.java"],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+
+    sdk_version: "test_current",
+}
diff --git a/tests/fragment/Android.mk b/tests/fragment/Android.mk
deleted file mode 100644
index 94a4d91..0000000
--- a/tests/fragment/Android.mk
+++ /dev/null
@@ -1,49 +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_PACKAGE_NAME := CtsFragmentTestCases
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    android-support-test \
-    mockito-target-minus-junit4 \
-    android-common \
-    compatibility-device-util \
-    ctstestrunner
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-#LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/fragment/AndroidTest.xml b/tests/fragment/AndroidTest.xml
index ed97400..902b754 100644
--- a/tests/fragment/AndroidTest.xml
+++ b/tests/fragment/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <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" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsFragmentTestCases.apk" />
diff --git a/tests/fragment/TEST_MAPPING b/tests/fragment/TEST_MAPPING
new file mode 100644
index 0000000..a5be057
--- /dev/null
+++ b/tests/fragment/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsFragmentTestCases"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/fragment/sdk26/Android.bp b/tests/fragment/sdk26/Android.bp
new file mode 100644
index 0000000..303c3cd
--- /dev/null
+++ b/tests/fragment/sdk26/Android.bp
@@ -0,0 +1,36 @@
+// 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.
+
+android_test {
+    name: "CtsFragmentTestCasesSdk26",
+    defaults: ["cts_defaults"],
+
+    optimize: {
+        enabled: false,
+    },
+
+    static_libs: ["android-support-test"],
+
+    srcs: ["src/**/*.java"],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+
+    sdk_version: "26",
+}
diff --git a/tests/fragment/sdk26/Android.mk b/tests/fragment/sdk26/Android.mk
deleted file mode 100644
index 5947137..0000000
--- a/tests/fragment/sdk26/Android.mk
+++ /dev/null
@@ -1,40 +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_PACKAGE_NAME := CtsFragmentTestCasesSdk26
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_SDK_VERSION := 26
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/fragment/sdk26/AndroidTest.xml b/tests/fragment/sdk26/AndroidTest.xml
index 16ffd27..baad0aa 100644
--- a/tests/fragment/sdk26/AndroidTest.xml
+++ b/tests/fragment/sdk26/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <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" />
     <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/fragment/sdk26/TEST_MAPPING b/tests/fragment/sdk26/TEST_MAPPING
new file mode 100644
index 0000000..28bdfed
--- /dev/null
+++ b/tests/fragment/sdk26/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsFragmentTestCasesSdk26"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml b/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml
index 04cace4..5085834 100644
--- a/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml
+++ b/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml
@@ -37,6 +37,9 @@
     <public type="attr" name="targetSdkVersion" id="0x01010270" />
     <attr name="targetSdkVersion" format="integer|string" />
 
+    <public type="attr" name="extractNativeLibs" id="0x10104ea" />
+    <attr name="extractNativeLibs" format="boolean" />
+
     <public type="attr" name="compileSdkVersion" id="0x01010572" />
     <attr name="compileSdkVersion" format="integer" />
 
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
index 7d32409..201495e 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
@@ -23,6 +23,7 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import android.platform.test.annotations.Presubmit;
 import android.server.am.CommandSession.ActivityCallback;
 
 import org.junit.Test;
@@ -31,6 +32,7 @@
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityAndWindowManagerOverrideConfigTests
  */
+@Presubmit
 public class ActivityAndWindowManagerOverrideConfigTests extends ActivityManagerTestBase {
 
     @Test
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
index 74f4546..da5c3fc 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
@@ -27,6 +27,7 @@
 
 import android.content.ComponentName;
 
+import android.platform.test.annotations.Presubmit;
 import org.junit.Test;
 
 /**
@@ -35,6 +36,7 @@
  *
  * Please talk to Android Studio team first if you want to modify or delete these tests.
  */
+@Presubmit
 public class ActivityManagerAmProfileTests extends ActivityManagerTestBase {
 
     private static final String OUTPUT_FILE_PATH = "/data/local/tmp/profile.trace";
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
index 80e16e2..b7a399b 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
@@ -58,6 +58,7 @@
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerConfigChangeTests
  */
+@Presubmit
 public class ActivityManagerConfigChangeTests extends ActivityManagerTestBase {
 
     private static final float EXPECTED_FONT_SIZE_SP = 10.0f;
@@ -102,7 +103,6 @@
     }
 
     @FlakyTest(bugId = 73701185)
-    @Presubmit
     @Test
     public void testChangeFontScaleRelaunch() throws Exception {
         // Should relaunch and receive no onConfigurationChanged()
@@ -110,7 +110,6 @@
     }
 
     @FlakyTest(bugId = 73812451)
-    @Presubmit
     @Test
     public void testChangeFontScaleNoRelaunch() throws Exception {
         // Should receive onConfigurationChanged() and no relaunch
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java
index 7416460..6b3df7c 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assume.assumeTrue;
 
+import android.platform.test.annotations.Presubmit;
 import android.server.am.ActivityManagerState.ActivityDisplay;
 
 import org.junit.Before;
@@ -35,6 +36,7 @@
  * <p>Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerDisplayKeyguardTests
  */
+@Presubmit
 public class ActivityManagerDisplayKeyguardTests extends ActivityManagerDisplayTestBase {
 
     @Before
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java
index bc6171a..2d59191 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java
@@ -26,6 +26,7 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import android.platform.test.annotations.Presubmit;
 import android.server.am.ActivityManagerState.ActivityDisplay;
 
 import org.junit.Before;
@@ -37,6 +38,7 @@
  * <p>Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerDisplayLockedKeyguardTests
  */
+@Presubmit
 public class ActivityManagerDisplayLockedKeyguardTests extends ActivityManagerDisplayTestBase {
 
     @Before
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
index 0d4ed6e..47108de 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
@@ -26,6 +26,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
 import android.server.am.ActivityManagerState.ActivityStack;
 import android.server.am.ActivityManagerState.ActivityTask;
 import android.view.Display;
@@ -36,6 +37,7 @@
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerFreeformStackTests
  */
+@Presubmit
 public class ActivityManagerFreeformStackTests extends ActivityManagerDisplayTestBase {
 
     private static final int TEST_TASK_OFFSET = 20;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerGetConfigTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerGetConfigTests.java
index a6d5b57..042d15f 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerGetConfigTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerGetConfigTests.java
@@ -38,6 +38,7 @@
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.Presubmit;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.view.Display;
@@ -64,6 +65,7 @@
 import javax.microedition.khronos.egl.EGLDisplay;
 import javax.microedition.khronos.egl.EGLSurface;
 
+@Presubmit
 public class ActivityManagerGetConfigTests {
     Context mContext;
     ActivityManager mAm;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java
index 420ebd05..c62e71f 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java
@@ -28,6 +28,7 @@
 import android.content.ComponentName;
 import android.os.SystemClock;
 
+import android.platform.test.annotations.Presubmit;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -38,6 +39,7 @@
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerReplaceWindowTests
  */
+@Presubmit
 public class ActivityManagerReplaceWindowTests extends ActivityManagerTestBase {
 
     @Before
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
index 589302a..6dbcaa9 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
@@ -30,6 +30,7 @@
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
+import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 import android.server.am.ActivityManagerState.ActivityDisplay;
 import android.server.am.settings.SettingsSession;
@@ -44,6 +45,7 @@
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerVrDisplayTests
  */
+@Presubmit
 public class ActivityManagerVrDisplayTests extends ActivityManagerDisplayTestBase {
     private static final int VR_VIRTUAL_DISPLAY_WIDTH = 700;
     private static final int VR_VIRTUAL_DISPLAY_HEIGHT = 900;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java b/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java
index ed9bc11..54a1562 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java
@@ -19,6 +19,7 @@
 import static android.server.am.UiDeviceUtils.pressBackButton;
 import static android.server.am.deprecatedsdk.Components.MAIN_ACTIVITY;
 
+import android.platform.test.annotations.Presubmit;
 import org.junit.After;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@
  * <p>Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:DeprecatedTargetSdkTest
  */
+@Presubmit
 public class DeprecatedTargetSdkTest extends ActivityManagerTestBase {
 
     /** @see com.android.server.wm.DeprecatedTargetSdkVersionDialog */
diff --git a/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java b/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
index f69a949..aa07257 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
@@ -28,6 +28,7 @@
 
 import android.os.Build;
 
+import android.platform.test.annotations.Presubmit;
 import org.junit.After;
 import org.junit.Test;
 
@@ -38,6 +39,7 @@
  * <p>Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:DisplaySizeTest
  */
+@Presubmit
 public class DisplaySizeTest extends ActivityManagerTestBase {
 
     /** @see com.android.server.am.UnsupportedDisplaySizeDialog */
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
index 427a2a0..7757076 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
@@ -33,6 +33,7 @@
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
+import android.platform.test.annotations.Presubmit;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -40,6 +41,7 @@
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:KeyguardTransitionTests
  */
+@Presubmit
 public class KeyguardTransitionTests extends ActivityManagerTestBase {
 
     @Before
diff --git a/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java b/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java
index b7703a8..71803f3 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java
@@ -19,6 +19,7 @@
 import static android.server.am.UiDeviceUtils.pressBackButton;
 import static android.server.am.prerelease.Components.MAIN_ACTIVITY;
 
+import android.platform.test.annotations.Presubmit;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.After;
@@ -31,6 +32,7 @@
  * <p>Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:PrereleaseSdkTest
  */
+@Presubmit
 public class PrereleaseSdkTest extends ActivityManagerTestBase {
 
     /** @see com.android.server.wm.UnsupportedCompileSdkDialog */
diff --git a/tests/framework/base/activitymanager/src/android/server/am/SplashscreenTests.java b/tests/framework/base/activitymanager/src/android/server/am/SplashscreenTests.java
index bf7a812..539e0f8 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/SplashscreenTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/SplashscreenTests.java
@@ -27,12 +27,14 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 
+import android.platform.test.annotations.Presubmit;
 import org.junit.Test;
 
 /**
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:SplashscreenTests
  */
+@Presubmit
 public class SplashscreenTests extends ActivityManagerTestBase {
 
     @Test
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
index 328d27e..c568d19 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
@@ -148,7 +148,8 @@
      * Blocking call that will wait for activities to reach expected states with timeout.
      */
     @SafeVarargs
-    final void waitAndAssertActivityStates(Pair<Activity, ActivityCallback>... activityCallbacks) {
+    final void waitAndAssertActivityStates(
+            Pair<Class<? extends Activity>, ActivityCallback>... activityCallbacks) {
         log("Start waitAndAssertActivityCallbacks");
         mLifecycleTracker.waitAndAssertActivityStates(activityCallbacks);
     }
@@ -181,15 +182,16 @@
         return mLifecycleLog;
     }
 
-    static Pair<Activity, ActivityCallback> state(Activity activity, ActivityCallback stage) {
-        return new Pair<>(activity, stage);
+    static Pair<Class<? extends Activity>, ActivityCallback> state(Activity activity,
+            ActivityCallback stage) {
+        return new Pair<>(activity.getClass(), stage);
     }
 
     /**
      * Returns a pair of the activity and the state it should be in based on the configuration of
      * occludingActivity.
      */
-    static Pair<Activity, ActivityCallback> occludedActivityState(
+    static Pair<Class<? extends Activity>, ActivityCallback> occludedActivityState(
             Activity activity, Activity occludingActivity) {
         return occludedActivityState(activity, isTranslucent(occludingActivity));
     }
@@ -198,11 +200,11 @@
      * Returns a pair of the activity and the state it should be in based on
      * occludingActivityIsTranslucent.
      */
-    static Pair<Activity, ActivityCallback> occludedActivityState(
+    static Pair<Class<? extends Activity>, ActivityCallback> occludedActivityState(
             Activity activity, boolean occludingActivityIsTranslucent) {
         // Activities behind a translucent activity should be in the paused state since they are
         // still visible. Otherwise, they should be in the stopped state.
-        return new Pair<>(activity, occludedActivityState(occludingActivityIsTranslucent));
+        return state(activity, occludedActivityState(occludingActivityIsTranslucent));
     }
 
     static ActivityCallback occludedActivityState(boolean occludingActivityIsTranslucent) {
@@ -352,4 +354,15 @@
     static ComponentName getComponentName(Class<? extends Activity> activity) {
         return new ComponentName(getInstrumentation().getContext(), activity);
     }
+
+    void moveTaskToPrimarySplitScreenAndVerify(Activity activity) {
+        getLifecycleLog().clear();
+
+        moveTaskToPrimarySplitScreen(activity.getTaskId());
+
+        final Class<? extends Activity> activityClass = activity.getClass();
+        waitAndAssertActivityTransitions(activityClass,
+                LifecycleVerifier.getSplitScreenTransitionSequence(activityClass),
+                "enterSplitScreen");
+    }
 }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java
index 044f5bc..bab51ac 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java
@@ -77,10 +77,8 @@
         // Wait and assert resume
         waitAndAssertActivityState(getComponentName(FirstActivity.class), STATE_RESUMED,
                 "Activity should be resumed after launch");
-        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
     }
 
     @Test
@@ -112,14 +110,10 @@
         waitAndAssertActivityState(getComponentName(ThirdActivity.class), STATE_RESUMED, message);
 
         // Assert lifecycle
-        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
     }
 
     @Test
@@ -152,12 +146,9 @@
 
         // Assert lifecycle
         LifecycleVerifier.assertLaunchAndStopSequence(FirstActivity.class, getLifecycleLog());
-        LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
 
         // Finish the activity that was occluding the first one
         getLifecycleLog().clear();
@@ -213,12 +204,9 @@
 
         // Assert lifecycle
         LifecycleVerifier.assertLaunchAndPauseSequence(FirstActivity.class, getLifecycleLog());
-        LifecycleVerifier.assertLaunchSequence(TranslucentActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
-        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(TranslucentActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
+        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
 
         // Finish the activity that was occluding the first one
         getLifecycleLog().clear();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java
index 00138cf..ab99a58 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java
@@ -91,7 +91,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
 
         // Enter split screen
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         // Launch second activity to side
         final Activity secondActivity = mSecondActivityTestRule.launchActivity(
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java
index 0fbc0ca..8a77fcb 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java
@@ -154,8 +154,7 @@
 
         // Wait and verify the sequence
         waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
-        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
         LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
                 "launchBelowPip");
     }
@@ -225,17 +224,10 @@
                         .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK));
 
         waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
-        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
 
         // Enter split screen
-        getLifecycleLog().clear();
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
-        LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
-                Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE, ON_START,
-                        ON_RESUME, ON_PAUSE), "moveToSplitScreen");
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
         // TODO(b/123013403): will fail with callback tracking enabled - delivers extra
         // MULTI_WINDOW_MODE_CHANGED
         LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
@@ -248,8 +240,7 @@
 
         // Wait for activities to resume and verify lifecycle
         waitAndAssertActivityStates(state(secondActivity, ON_RESUME));
-        LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
         LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
                 Arrays.asList(ON_RESUME), "launchToSide");
         LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
@@ -263,7 +254,7 @@
                 mFirstActivityTestRule.launchActivity(new Intent());
 
         // Enter split screen
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         // Launch second activity to side
         final Activity secondActivity = mSecondActivityTestRule.launchActivity(
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java
index 7707f1b..4950aa6 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java
@@ -50,6 +50,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -84,7 +85,7 @@
                 state(firstActivity, ON_STOP));
 
         // Enter split screen
-        moveTaskToPrimarySplitScreen(secondActivity.getTaskId());
+        moveTaskToPrimarySplitScreenAndVerify(secondActivity);
 
         // CLear logs so we can capture just the destroy sequence
         getLifecycleLog().clear();
@@ -111,8 +112,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
 
         // Enter split screen
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         final ComponentName firstActivityName = getComponentName(FirstActivity.class);
         mAmWmState.computeState(firstActivityName);
@@ -142,7 +142,9 @@
 
         waitAndAssertActivityStates(state(secondActivity, ON_RESUME),
                 state(firstActivity, ON_STOP));
-        LifecycleVerifier.assertEmptySequence(ThirdActivity.class, getLifecycleLog(), "moveToSide");
+        LifecycleVerifier.assertSequenceMatchesOneOf(ThirdActivity.class, getLifecycleLog(),
+                Arrays.asList(new ArrayList<>(), LifecycleVerifier.getRelaunchSequence(ON_RESUME)),
+                "moveToSide");
         LifecycleVerifier.assertRestartAndResumeSequence(SecondActivity.class, getLifecycleLog());
         LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
                 Arrays.asList(ON_PAUSE, ON_STOP), "moveToSide");
@@ -156,8 +158,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
 
         // Enter split screen
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         final ComponentName firstActivityName = getComponentName(FirstActivity.class);
         mAmWmState.computeState(firstActivityName);
@@ -179,19 +180,15 @@
 
         final Activity translucentActivity = mTranslucentActivityTestRule.launchActivity(
                 new Intent().setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK));
-        waitAndAssertActivityStates(state(translucentActivity, ON_RESUME));
-        // Second activity should stay resumed, because it's in a separate stack below the
-        // translucent activity.
-        LifecycleVerifier.assertEmptySequence(SecondActivity.class, getLifecycleLog(),
-                "moveToSide");
+        waitAndAssertActivityStates(state(translucentActivity, ON_RESUME),
+                state(secondActivity, ON_PAUSE));
 
         // Move translucent activity to side, it will be on top of the first now
         getLifecycleLog().clear();
         moveActivityToStack(getComponentName(TranslucentActivity.class), primarySplitStack);
 
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
-        LifecycleVerifier.assertEmptySequence(SecondActivity.class, getLifecycleLog(),
-                "moveToSide");
+        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE),
+                state(secondActivity, ON_RESUME));
         LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
                 Arrays.asList(ON_PAUSE), "moveToSide");
         // Translucent activity can be either relaunched or preserved depending on whether the split
@@ -208,16 +205,7 @@
         waitAndAssertActivityStates(state(callbackTrackingActivity, ON_TOP_POSITION_GAINED));
 
         // Enter split screen, the activity will be relaunched.
-        getLifecycleLog().clear();
-        moveTaskToPrimarySplitScreen(callbackTrackingActivity.getTaskId());
-        // Wait for multi-window mode change that will come after activity relaunch and resume.
-        waitAndAssertActivityStates(state(callbackTrackingActivity, ON_PAUSE));
-        final List<LifecycleLog.ActivityCallback> splitScreenMoveSequence = Arrays.asList(
-                ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE,
-                ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
-                ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST, ON_PAUSE);
-        LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                splitScreenMoveSequence, "moveToPrimarySplitScreen");
+        moveTaskToPrimarySplitScreenAndVerify(callbackTrackingActivity);
         getLifecycleLog().clear();
 
         // Launch second activity
@@ -268,12 +256,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
 
         // Enter split screen
-        getLifecycleLog().clear();
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
-        LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(), Arrays.asList(
-                ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME,
-                ON_PAUSE), "enterSplitScreen");
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         // Start an activity in separate task (will be placed in secondary stack)
         final Activity newTaskActivity = mThirdActivityTestRule.launchActivity(
@@ -353,8 +336,7 @@
 
         // Wait for the activity to resume
         waitAndAssertActivityStates(state(testActivity, ON_TOP_POSITION_GAINED));
-        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
 
         // Enter split screen
         getLifecycleLog().clear();
@@ -402,7 +384,7 @@
         // Wait for the activity to resume
         waitAndAssertActivityStates(state(testActivity, ON_TOP_POSITION_GAINED));
         LifecycleVerifier.assertLaunchSequence(ConfigChangeHandlingActivity.class,
-                getLifecycleLog(), true /* includeCallbacks */);
+                getLifecycleLog());
 
         // Enter split screen
         getLifecycleLog().clear();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
index d20f1b3..f9b25bb 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
@@ -71,8 +71,7 @@
         final Activity activity = mFirstActivityTestRule.launchActivity(new Intent());
         waitAndAssertActivityStates(state(activity, ON_RESUME));
 
-        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
-                false /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
     }
 
     @Test
@@ -654,8 +653,7 @@
 
         // Wait for the activity to resume
         waitAndAssertActivityStates(state(singleTopActivity, ON_TOP_POSITION_GAINED));
-        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
 
         // Try to launch again
         getLifecycleLog().clear();
@@ -680,8 +678,7 @@
 
         // Wait for the activity to resume
         waitAndAssertActivityStates(state(singleTopActivity, ON_TOP_POSITION_GAINED));
-        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
 
         // Launch something on top
         final Intent newTaskIntent = new Intent();
@@ -724,8 +721,7 @@
 
         // Wait for the activity to resume
         waitAndAssertActivityStates(state(singleTopActivity, ON_TOP_POSITION_GAINED));
-        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
 
         // Launch translucent activity, which will make the first one paused.
         mTranslucentActivityTestRule.launchActivity(new Intent());
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java
index df99ae8..0dd03be 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java
@@ -9,7 +9,6 @@
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_ACTIVITY_RESULT;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_CREATE;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_DESTROY;
-import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_NEW_INTENT;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_PAUSE;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_POST_CREATE;
@@ -59,8 +58,7 @@
         final Activity activity = mCallbackTrackingActivityTestRule.launchActivity(new Intent());
         waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
 
-        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
     }
 
     @Test
@@ -73,7 +71,7 @@
         mAmWmState.waitForActivityRemoved(getComponentName(CallbackTrackingActivity.class));
 
         LifecycleVerifier.assertResumeToDestroySequence(CallbackTrackingActivity.class,
-                getLifecycleLog(), true /* includeCallbacks */);
+                getLifecycleLog());
     }
 
     @Test
@@ -88,7 +86,7 @@
 
         LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class,
                 CallbackTrackingActivity.class, getLifecycleLog(),
-                false /* launchingIsTranslucent */, true /* includingCallbacks */);
+                false /* launchingIsTranslucent */);
     }
 
     @Test
@@ -104,7 +102,7 @@
 
         LifecycleVerifier.assertLaunchSequence(TranslucentCallbackTrackingActivity.class,
                 CallbackTrackingActivity.class, getLifecycleLog(),
-                true /* launchingIsTranslucent */, true /* includingCallbacks */);
+                true /* launchingIsTranslucent */);
     }
 
     @Test
@@ -209,14 +207,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
 
         // Enter split screen
-        getLifecycleLog().clear();
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
-        LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
-                Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE,
-                        ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
-                        ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST, ON_PAUSE),
-                "moveToDocked");
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
     }
 
     @Test
@@ -229,9 +220,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
 
         // Enter split screen
-        getLifecycleLog().clear();
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         // Launch second activity to side
         getLifecycleLog().clear();
@@ -245,8 +234,7 @@
         LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
                 Arrays.asList(ON_RESUME), "unminimizeDockedStack");
         // Second activity must be on top now
-        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+        LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
     }
 
     @Test
@@ -259,9 +247,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
 
         // Enter split screen
-        getLifecycleLog().clear();
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         // Launch second activity to side
         getLifecycleLog().clear();
@@ -396,7 +382,7 @@
         waitAndAssertActivityStates(state(topActivity, ON_STOP));
 
         LifecycleVerifier.assertResumeToStopSequence(CallbackTrackingActivity.class,
-                getLifecycleLog(), true /* includeCallbacks */);
+                getLifecycleLog());
     }
 
     @Test
@@ -409,9 +395,7 @@
         waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
 
         // Enter split screen
-        getLifecycleLog().clear();
-        moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-        waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+        moveTaskToPrimarySplitScreenAndVerify(firstActivity);
 
         // Launch second activity to side
         getLifecycleLog().clear();
@@ -480,7 +464,7 @@
                     new Intent());
             waitAndAssertActivityStates(state(activity, ON_STOP));
             LifecycleVerifier.assertLaunchAndStopSequence(CallbackTrackingActivity.class,
-                    getLifecycleLog(), true /* includeCallbacks */, false /* onTop */);
+                    getLifecycleLog(), false /* onTop */);
 
             getLifecycleLog().clear();
         }
@@ -488,7 +472,7 @@
         // Lock screen removed - activity should be on top now
         waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
         LifecycleVerifier.assertStopToResumeSequence(CallbackTrackingActivity.class,
-                getLifecycleLog(), true /* includeCallbacks */);
+                getLifecycleLog());
     }
 
     @Test
@@ -504,7 +488,7 @@
 
             waitAndAssertActivityStates(state(activity, ON_STOP));
             LifecycleVerifier.assertResumeToStopSequence(CallbackTrackingActivity.class,
-                    getLifecycleLog(), true /* includeCallbacks */);
+                    getLifecycleLog());
 
             getLifecycleLog().clear();
         }
@@ -512,7 +496,7 @@
         // Lock screen removed - activity should be on top now
         waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
         LifecycleVerifier.assertStopToResumeSequence(CallbackTrackingActivity.class,
-                getLifecycleLog(), true /* includeCallbacks */);
+                getLifecycleLog());
     }
 
     @Test
@@ -540,8 +524,7 @@
         // Wait for something here, but don't expect anything to happen.
         waitAndAssertActivityStates(state(showWhenLockedActivity, ON_DESTROY));
         LifecycleVerifier.assertResumeToDestroySequence(
-                ShowWhenLockedCallbackTrackingActivity.class, getLifecycleLog(),
-                true /* includeCallbacks */);
+                ShowWhenLockedCallbackTrackingActivity.class, getLifecycleLog());
     }
 
     @Test
@@ -558,7 +541,7 @@
         waitAndAssertTopResumedActivity(getComponentName(CallbackTrackingActivity.class),
                 DEFAULT_DISPLAY, "Activity launched on default display must be focused");
         waitAndAssertActivityTransitions(CallbackTrackingActivity.class,
-                LifecycleVerifier.getLaunchSequence(true /* includeCallbacks */), "launch");
+                LifecycleVerifier.getLaunchSequence(CallbackTrackingActivity.class), "launch");
 
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             // Create new simulated display
@@ -575,7 +558,7 @@
                     newDisplay.mId, "Activity launched on secondary display must be focused");
 
             waitAndAssertActivityTransitions(SingleTopActivity.class,
-                    LifecycleVerifier.getLaunchSequence(true /* includeCallbacks */), "launch");
+                    LifecycleVerifier.getLaunchSequence(SingleTopActivity.class), "launch");
             LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
                     transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
                     transition(SingleTopActivity.class, ON_TOP_POSITION_GAINED)),
@@ -586,7 +569,7 @@
 
         // Secondary display was removed - activity will be moved to the default display
         waitAndAssertActivityTransitions(SingleTopActivity.class,
-                LifecycleVerifier.getResumeToDestroySequence(true /* includeCallbacks */),
+                LifecycleVerifier.getResumeToDestroySequence(SingleTopActivity.class),
                 "hostingDisplayRemoved");
         waitAndAssertActivityTransitions(CallbackTrackingActivity.class,
                 Arrays.asList(ON_TOP_POSITION_GAINED, ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP),
@@ -734,7 +717,7 @@
         waitAndAssertActivityStates(state(alwaysFocusableActivity, ON_DESTROY),
                 state(activity, ON_TOP_POSITION_GAINED), state(pipActivity, ON_PAUSE));
         LifecycleVerifier.assertResumeToDestroySequence(AlwaysFocusablePipActivity.class,
-                getLifecycleLog(), true /* includeCallbacks */);
+                getLifecycleLog());
         LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
                 transition(AlwaysFocusablePipActivity.class, ON_TOP_POSITION_LOST),
                 transition(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED)),
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java
index 25374e5..24eb301 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java
@@ -40,7 +40,8 @@
         mLifecycleLog = lifecycleLog;
     }
 
-    void waitAndAssertActivityStates(Pair<Activity, ActivityCallback>[] activityCallbacks) {
+    void waitAndAssertActivityStates(
+            Pair<Class<? extends Activity>, ActivityCallback>[] activityCallbacks) {
         final boolean waitResult = waitForConditionWithTimeout(
                 () -> pendingCallbacks(activityCallbacks).isEmpty(), 5 * 1000);
 
@@ -68,19 +69,20 @@
     }
 
     /** Get a list of activity states that were not reached yet. */
-    private List<Pair<Activity, ActivityCallback>> pendingCallbacks(Pair<Activity,
-            ActivityCallback>[] activityCallbacks) {
-        final List<Pair<Activity, ActivityCallback>> notReachedActivityCallbacks = new ArrayList<>();
+    private List<Pair<Class<? extends Activity>, ActivityCallback>> pendingCallbacks(
+            Pair<Class<? extends Activity>, ActivityCallback>[] activityCallbacks) {
+        final List<Pair<Class<? extends Activity>, ActivityCallback>> notReachedActivityCallbacks =
+                new ArrayList<>();
 
-        for (Pair<Activity, ActivityCallback> activityCallback : activityCallbacks) {
-            final Activity activity = activityCallback.first;
+        for (Pair<Class<? extends Activity>, ActivityCallback> callbackPair : activityCallbacks) {
+            final Class<? extends Activity> activityClass = callbackPair.first;
             final List<ActivityCallback> transitionList =
-                    mLifecycleLog.getActivityLog(activity.getClass());
+                    mLifecycleLog.getActivityLog(activityClass);
             if (transitionList.isEmpty()
-                    || transitionList.get(transitionList.size() - 1) != activityCallback.second) {
+                    || transitionList.get(transitionList.size() - 1) != callbackPair.second) {
                 // The activity either hasn't got any state transitions yet or the current state is
                 // not the one we expect.
-                notReachedActivityCallbacks.add(activityCallback);
+                notReachedActivityCallbacks.add(callbackPair);
             }
         }
         return notReachedActivityCallbacks;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
index 1f35d1f..a289682 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
@@ -19,6 +19,7 @@
 import static android.server.am.StateLogger.log;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_CREATE;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_DESTROY;
+import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_PAUSE;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_POST_CREATE;
 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_RESTART;
@@ -34,6 +35,7 @@
 import static org.junit.Assert.fail;
 
 import android.app.Activity;
+import android.server.am.lifecycle.ActivityLifecycleClientTestBase.CallbackTrackingActivity;
 import android.server.am.lifecycle.LifecycleLog.ActivityCallback;
 import android.util.Pair;
 
@@ -44,19 +46,22 @@
 /** Util class that verifies correct activity state transition sequences. */
 class LifecycleVerifier {
 
+    private static final Class CALLBACK_TRACKING_CLASS = CallbackTrackingActivity.class;
+
     static void assertLaunchSequence(Class<? extends Activity> activityClass,
-            LifecycleLog lifecycleLog, boolean includeCallbacks) {
+            LifecycleLog lifecycleLog) {
         final List<ActivityCallback> observedTransitions =
                 lifecycleLog.getActivityLog(activityClass);
         log("Observed sequence: " + observedTransitions);
         final String errorMessage = errorDuringTransition(activityClass, "launch");
 
-        final List<ActivityCallback> expectedTransitions = getLaunchSequence(includeCallbacks);
+        final List<ActivityCallback> expectedTransitions = getLaunchSequence(activityClass);
         assertEquals(errorMessage, expectedTransitions, observedTransitions);
     }
 
-    public static List<ActivityCallback> getLaunchSequence(boolean includeCallbacks) {
-        return includeCallbacks
+    public static List<ActivityCallback> getLaunchSequence(
+            Class<? extends Activity> activityClass) {
+        return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass)
                 ? Arrays.asList(PRE_ON_CREATE, ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME,
                 ON_TOP_POSITION_GAINED)
                 : Arrays.asList(PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME);
@@ -65,13 +70,20 @@
     static void assertLaunchSequence(Class<? extends Activity> launchingActivity,
             Class<? extends Activity> existingActivity, LifecycleLog lifecycleLog,
             boolean launchingIsTranslucent) {
-        assertLaunchSequence(launchingActivity, existingActivity, lifecycleLog,
-                launchingIsTranslucent, false /* includingCallbacks */);
-    }
+        final boolean includingCallbacks;
+        if (CALLBACK_TRACKING_CLASS.isAssignableFrom(launchingActivity)
+                && CALLBACK_TRACKING_CLASS.isAssignableFrom(existingActivity)) {
+            includingCallbacks = true;
+        } else if (!CALLBACK_TRACKING_CLASS.isAssignableFrom(launchingActivity)
+                && !CALLBACK_TRACKING_CLASS.isAssignableFrom(existingActivity)) {
+            includingCallbacks = false;
+        } else {
+            throw new IllegalArgumentException("Mixed types of callback tracking not supported. "
+                    + "Both activities must support or not support callback tracking "
+                    + "simultaneously");
+        }
 
-    static void assertLaunchSequence(Class<? extends Activity> launchingActivity,
-            Class<? extends Activity> existingActivity, LifecycleLog lifecycleLog,
-            boolean launchingIsTranslucent, boolean includingCallbacks) {
+
         final List<Pair<String, ActivityCallback>> observedTransitions = lifecycleLog.getLog();
         log("Observed sequence: " + observedTransitions);
         final String errorMessage = errorDuringTransition(launchingActivity, "launch");
@@ -102,17 +114,19 @@
 
     static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass,
             LifecycleLog lifecycleLog) {
-        assertLaunchAndStopSequence(activityClass, lifecycleLog, false /* includeCallbacks */,
+        assertLaunchAndStopSequence(activityClass, lifecycleLog,
                 false /* onTop */);
     }
 
     static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass,
-            LifecycleLog lifecycleLog, boolean includeCallbacks, boolean onTop) {
+            LifecycleLog lifecycleLog, boolean onTop) {
         final List<ActivityCallback> observedTransitions =
                 lifecycleLog.getActivityLog(activityClass);
         log("Observed sequence: " + observedTransitions);
         final String errorMessage = errorDuringTransition(activityClass, "launch and stop");
 
+        final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
+
         final List<ActivityCallback> expectedTransitions = new ArrayList<>();
         expectedTransitions.addAll(Arrays.asList(PRE_ON_CREATE, ON_CREATE, ON_START));
         if (includeCallbacks) {
@@ -151,7 +165,7 @@
     }
 
     static void assertRestartAndResumeSequence(Class<? extends Activity> activityClass,
-                                              LifecycleLog lifecycleLog) {
+            LifecycleLog lifecycleLog) {
         final List<ActivityCallback> observedTransitions =
                 lifecycleLog.getActivityLog(activityClass);
         log("Observed sequence: " + observedTransitions);
@@ -163,7 +177,7 @@
     }
 
     static void assertRecreateAndResumeSequence(Class<? extends Activity> activityClass,
-                                              LifecycleLog lifecycleLog) {
+            LifecycleLog lifecycleLog) {
         final List<ActivityCallback> observedTransitions =
                 lifecycleLog.getActivityLog(activityClass);
         log("Observed sequence: " + observedTransitions);
@@ -188,38 +202,30 @@
 
     static void assertResumeToDestroySequence(Class<? extends Activity> activityClass,
             LifecycleLog lifecycleLog) {
-        assertResumeToDestroySequence(activityClass, lifecycleLog, false /* includeCallbacks */);
-    }
-
-    static void assertResumeToDestroySequence(Class<? extends Activity> activityClass,
-            LifecycleLog lifecycleLog, boolean includeCallbacks) {
         final List<ActivityCallback> observedTransitions =
                 lifecycleLog.getActivityLog(activityClass);
         log("Observed sequence: " + observedTransitions);
         final String errorMessage = errorDuringTransition(activityClass, "launch and destroy");
 
         final List<ActivityCallback> expectedTransitions =
-                getResumeToDestroySequence(includeCallbacks);
+                getResumeToDestroySequence(activityClass);
         assertEquals(errorMessage, expectedTransitions, observedTransitions);
     }
 
-    static List<ActivityCallback> getResumeToDestroySequence(boolean includeCallbacks) {
-        return includeCallbacks
+    static List<ActivityCallback> getResumeToDestroySequence(
+            Class<? extends Activity> activityClass) {
+        return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass)
                 ? Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY)
                 : Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY);
     }
 
     static void assertResumeToStopSequence(Class<? extends Activity> activityClass,
             LifecycleLog lifecycleLog) {
-        assertResumeToStopSequence(activityClass, lifecycleLog, false /* includeCallbacks */);
-    }
-
-    static void assertResumeToStopSequence(Class<? extends Activity> activityClass,
-            LifecycleLog lifecycleLog, boolean includeCallbacks) {
         final List<ActivityCallback> observedTransitions =
                 lifecycleLog.getActivityLog(activityClass);
         log("Observed sequence: " + observedTransitions);
         final String errorMessage = errorDuringTransition(activityClass, "resumed to stopped");
+        final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
 
         final List<ActivityCallback> expectedTransitions = new ArrayList<>();
         if (includeCallbacks) {
@@ -232,11 +238,12 @@
     }
 
     static void assertStopToResumeSequence(Class<? extends Activity> activityClass,
-            LifecycleLog lifecycleLog, boolean includeCallbacks) {
+            LifecycleLog lifecycleLog) {
         final List<ActivityCallback> observedTransitions =
                 lifecycleLog.getActivityLog(activityClass);
         log("Observed sequence: " + observedTransitions);
         final String errorMessage = errorDuringTransition(activityClass, "stopped to resumed");
+        final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
 
         final List<ActivityCallback> expectedTransitions = new ArrayList<>(
                 Arrays.asList(ON_RESTART, ON_START, ON_RESUME));
@@ -249,6 +256,11 @@
 
     static void assertRelaunchSequence(Class<? extends Activity> activityClass,
             LifecycleLog lifecycleLog, ActivityCallback startState) {
+        final List<ActivityCallback> expectedTransitions = getRelaunchSequence(startState);
+        assertSequence(activityClass, lifecycleLog, expectedTransitions, "relaunch");
+    }
+
+    static List<ActivityCallback> getRelaunchSequence(ActivityCallback startState) {
         final List<ActivityCallback> expectedTransitions;
         if (startState == ON_PAUSE) {
             expectedTransitions = Arrays.asList(
@@ -267,7 +279,17 @@
         } else {
             throw new IllegalArgumentException("Start state not supported: " + startState);
         }
-        assertSequence(activityClass, lifecycleLog, expectedTransitions, "relaunch");
+        return expectedTransitions;
+    }
+
+    static List<ActivityCallback> getSplitScreenTransitionSequence(
+            Class<? extends Activity> activityClass) {
+        return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass)
+                ? Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE,
+                ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
+                ON_TOP_POSITION_LOST, ON_PAUSE, ON_MULTI_WINDOW_MODE_CHANGED)
+                : Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE, ON_START,
+                ON_RESUME, ON_PAUSE);
     }
 
     static void assertSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog,
diff --git a/tests/framework/base/activitymanager/util/Android.bp b/tests/framework/base/activitymanager/util/Android.bp
index 2e2f030..f71603b 100644
--- a/tests/framework/base/activitymanager/util/Android.bp
+++ b/tests/framework/base/activitymanager/util/Android.bp
@@ -24,9 +24,7 @@
     static_libs: [
         "platformprotosnano",
         "compatibility-device-util",
-	"android-support-test",
-        "androidx.test.rules",
-        "androidx.test.runner",
+        "android-support-test",
     ],
 
     sdk_version: "test_current",
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java
deleted file mode 100644
index 3307af1..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java
+++ /dev/null
@@ -1,51 +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.server.am.compat;
-
-import com.android.compatibility.common.util.TestUtils;
-
-/**
- * {@link com.android.compatibility.common.util.AmUtils} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class AmUtils {
-
-    public static void runKill(String packageName, boolean wait) throws Exception {
-        SystemUtil.runShellCommandForNoOutput("am kill --user cur " + packageName);
-
-        if (!wait) {
-            return;
-        }
-
-        TestUtils.waitUntil("package process was not killed:" + packageName,
-                () -> !isProcessRunning(packageName));
-    }
-
-    private static boolean isProcessRunning(String packageName) {
-        final String output = SystemUtil.runShellCommand("ps -A -o NAME");
-        String[] packages = output.split("\\n");
-        for (int i = packages.length - 1; i >= 0; --i) {
-            if (packages[i].equals(packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java
deleted file mode 100644
index f957d14..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java
+++ /dev/null
@@ -1,128 +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.server.am.compat;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import android.app.AppOpsManager;
-
-import java.io.IOException;
-
-/**
- * {@link com.android.compatibility.common.util.AppOpsUtils} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class AppOpsUtils {
-    /**
-     * Resets a package's app ops configuration to the device default. See AppOpsManager for the
-     * default op settings.
-     *
-     * <p>
-     * It's recommended to call this in setUp() and tearDown() of your test so the test starts and
-     * ends with a reproducible default state, and so doesn't affect other tests.
-     *
-     * <p>
-     * Some app ops are configured to be non-resettable, which means that the state of these will
-     * not be reset even when calling this method.
-     */
-    public static String reset(String packageName) throws IOException {
-        return SystemUtil.runShellCommand(getInstrumentation(), "appops reset " + packageName);
-    }
-
-    /**
-     * Sets the app op mode (e.g. allowed, denied) for a single package and operation.
-     */
-    public static String setOpMode(String packageName, String opStr, int mode)
-            throws IOException {
-        String modeStr;
-        switch (mode) {
-            case AppOpsManager.MODE_ALLOWED:
-                modeStr = "allow";
-                break;
-            case AppOpsManager.MODE_ERRORED:
-                modeStr = "deny";
-                break;
-            case AppOpsManager.MODE_IGNORED:
-                modeStr = "ignore";
-                break;
-            case AppOpsManager.MODE_DEFAULT:
-                modeStr = "default";
-                break;
-            default:
-                throw new IllegalArgumentException("Unexpected app op type");
-        }
-        String command = "appops set " + packageName + " " + opStr + " " + modeStr;
-        return SystemUtil.runShellCommand(getInstrumentation(), command);
-    }
-
-    /**
-     * Get the app op mode (e.g. MODE_ALLOWED, MODE_DEFAULT) for a single package and operation.
-     */
-    public static int getOpMode(String packageName, String opStr)
-            throws IOException {
-        String opState = getOpState(packageName, opStr);
-        if (opState.contains(" allow")) {
-            return AppOpsManager.MODE_ALLOWED;
-        } else if (opState.contains(" deny")) {
-            return AppOpsManager.MODE_ERRORED;
-        } else if (opState.contains(" ignore")) {
-            return AppOpsManager.MODE_IGNORED;
-        } else if (opState.contains(" default")) {
-            return AppOpsManager.MODE_DEFAULT;
-        } else {
-            throw new IllegalStateException("Unexpected app op mode returned " + opState);
-        }
-    }
-
-    /**
-     * Returns whether an allowed operation has been logged by the AppOpsManager for a
-     * package. Operations are noted when the app attempts to perform them and calls e.g.
-     * {@link AppOpsManager#noteOp}.
-     *
-     * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
-     */
-    public static boolean allowedOperationLogged(String packageName, String opStr)
-            throws IOException {
-        return getOpState(packageName, opStr).contains(" time=");
-    }
-
-    /**
-     * Returns whether a rejected operation has been logged by the AppOpsManager for a
-     * package. Operations are noted when the app attempts to perform them and calls e.g.
-     * {@link AppOpsManager#noteOp}.
-     *
-     * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
-     */
-    public static boolean rejectedOperationLogged(String packageName, String opStr)
-            throws IOException {
-        return getOpState(packageName, opStr).contains(" rejectTime=");
-    }
-
-    /**
-     * Returns the app op state for a package. Includes information on when the operation was
-     * last attempted to be performed by the package.
-     *
-     * Format: "SEND_SMS: allow; time=+23h12m54s980ms ago; rejectTime=+1h10m23s180ms"
-     */
-    private static String getOpState(String packageName, String opStr) throws IOException {
-        return SystemUtil.runShellCommand(
-                getInstrumentation(), "appops get " + packageName + " " + opStr);
-    }
-}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java
deleted file mode 100644
index 23f8784..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java
+++ /dev/null
@@ -1,149 +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.server.am.compat;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.compatibility.common.util.ThrowingRunnable;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.concurrent.Callable;
-
-/**
- * {@link com.android.compatibility.common.util.SystemUtil} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class SystemUtil {
-
-    private static final String TAG = SystemUtil.class.getSimpleName();
-
-    /**
-     * Executes a shell command using shell user identity, and return the standard output in string
-     * <p>Note: calling this function requires API level 21 or above
-     * @param instrumentation {@link Instrumentation} instance, obtained from a test running in
-     * instrumentation framework
-     * @param cmd the command to run
-     * @return the standard output of the command
-     * @throws Exception
-     */
-    public static String runShellCommand(Instrumentation instrumentation, String cmd)
-            throws IOException {
-        Log.v(TAG, "Running command: " + cmd);
-        if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) {
-            throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() "
-                    + "or revokeRuntimePermission() directly, which are more robust.");
-        }
-        ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
-        byte[] buf = new byte[512];
-        int bytesRead;
-        FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-        StringBuffer stdout = new StringBuffer();
-        while ((bytesRead = fis.read(buf)) != -1) {
-            stdout.append(new String(buf, 0, bytesRead));
-        }
-        fis.close();
-        return stdout.toString();
-    }
-
-    /**
-     * Simpler version of {@link #runShellCommand(Instrumentation, String)}.
-     */
-    public static String runShellCommand(String cmd) {
-        try {
-            return runShellCommand(getInstrumentation(), cmd);
-        } catch (IOException e) {
-            fail("Failed reading command output: " + e);
-            return "";
-        }
-    }
-
-    /**
-     * Same as {@link #runShellCommand(String)}, but fails if the output is not empty.
-     */
-    public static String runShellCommandForNoOutput(String cmd) {
-        final String result = runShellCommand(cmd);
-        assertTrue("Command failed. Command was: " + cmd + "\n"
-                        + "Didn't expect any output, but the output was:\n" + result,
-                result.length() == 0);
-        return result;
-    }
-
-    /**
-     * Runs a {@link ThrowingRunnable} adopting Shell's permissions.
-     */
-    public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable) {
-        final UiAutomation automan = getInstrumentation().getUiAutomation();
-        runWithShellPermissionIdentity(automan, runnable, (String[]) null /* permissions */);
-    }
-
-    /**
-     * Runs a {@link ThrowingRunnable} adopting a subset of Shell's permissions.
-     */
-    public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable,
-            String... permissions) {
-        final UiAutomation automan = getInstrumentation().getUiAutomation();
-        runWithShellPermissionIdentity(automan, runnable, permissions);
-    }
-
-    /**
-     * Runs a {@link ThrowingRunnable} adopting Shell's permissions, where you can specify the
-     * uiAutomation used.
-     * @param automan UIAutomation to use.
-     * @param runnable The code to run with Shell's identity.
-     * @param permissions A subset of Shell's permissions. Passing {@code null} will use all
-     *                    available permissions.
-     */
-    private static void runWithShellPermissionIdentity(@NonNull UiAutomation automan,
-            @NonNull ThrowingRunnable runnable, String... permissions) {
-        automan.adoptShellPermissionIdentity(permissions);
-        try {
-            runnable.run();
-        } catch (Exception e) {
-            throw new RuntimeException("Caught exception", e);
-        } finally {
-            automan.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Calls a {@link Callable} adopting Shell's permissions.
-     */
-    public static <T> T callWithShellPermissionIdentity(@NonNull Callable<T> callable)
-            throws Exception {
-        final UiAutomation automan = getInstrumentation().getUiAutomation();
-        automan.adoptShellPermissionIdentity();
-        try {
-            return callable.call();
-        } finally {
-            automan.dropShellPermissionIdentity();
-        }
-    }
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java
index 78f3534..8f1543c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java
@@ -38,6 +38,7 @@
 import android.content.ComponentName;
 import android.graphics.Rect;
 import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.Presubmit;
 import android.server.am.WaitForValidActivityState;
 import android.server.am.WindowManagerState;
 import android.server.am.WindowManagerState.WindowState;
@@ -56,6 +57,7 @@
  * TODO: Consolidate this class with {@link ParentChildTestBase}.
  */
 @AppModeFull(reason = "Requires android.permission.MANAGE_ACTIVITY_STACKS")
+@Presubmit
 public class DialogFrameTests extends ParentChildTestBase<DialogFrameTestActivity> {
 
     private static final ComponentName DIALOG_FRAME_TEST_ACTIVITY = new ComponentName(
diff --git a/tests/providerui/AndroidTest.xml b/tests/providerui/AndroidTest.xml
index 6a123f6..9ef1d6c 100644
--- a/tests/providerui/AndroidTest.xml
+++ b/tests/providerui/AndroidTest.xml
@@ -16,7 +16,9 @@
 <configuration description="Config for CTS Provider UI test cases">
     <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" />
+    <!-- Instant apps cannot access external storage -->
+    <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="CtsProviderUiTestCases.apk" />
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
index c398ab05..e2a3139 100644
--- a/tests/sample/AndroidTest.xml
+++ b/tests/sample/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <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="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsSampleDeviceTestCases.apk" />
diff --git a/tests/signature/TEST_MAPPING b/tests/signature/TEST_MAPPING
new file mode 100644
index 0000000..5ed73ce
--- /dev/null
+++ b/tests/signature/TEST_MAPPING
@@ -0,0 +1,48 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAndroidTestMockCurrentApiSignatureTestCases"
+    },
+    {
+      "name": "CtsAndroidTestRunnerCurrentApiSignatureTestCases"
+    },
+    {
+      "name": "CtsApacheHttpLegacyCurrentApiSignatureTestCases"
+    },
+    {
+      "name": "CtsCurrentApiSignatureTestCases"
+    },
+    {
+      "name": "CtsAndroidTestBase27ApiSignatureTestCases"
+    },
+    {
+      "name": "CtsAndroidTestBase27ApiSignatureTestCases"
+    },
+    {
+      "name": "CtsApacheHttpLegacy27ApiSignatureTestCases"
+    },
+    {
+      "name": "CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases"
+    },
+    {
+      "name": "CtsHiddenApiKillswitchDebugClassTestCases"
+    },
+    {
+      "name": "CtsHiddenApiKillswitchWhitelistTestCases"
+    },
+    {
+      "name": "CtsHiddenApiKillswitchWildcardTestCases"
+    },
+    {
+      "name": "CtsSystemApiAnnotationTestCases"
+    },
+    {
+      "name": "CtsSharedLibsApiSignatureTestCases"
+    }
+  ]
+}
+
+
+
+
+
diff --git a/tests/signature/api-check/android-test-base-27-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-27-api/AndroidTest.xml
index bf07983..d746778 100644
--- a/tests/signature/api-check/android-test-base-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-27-api/AndroidTest.xml
@@ -30,7 +30,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.android_test_base_27" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.api27.test.SignatureTest" />
         <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.api" />
         <option name="runtime-hint" value="5s" />
     </test>
diff --git a/tests/signature/api-check/android-test-base-27-api/src/java/android/signature/cts/api/api27/test/SignatureTest.java b/tests/signature/api-check/android-test-base-27-api/src/java/android/signature/cts/api/api27/test/SignatureTest.java
new file mode 100644
index 0000000..875349a
--- /dev/null
+++ b/tests/signature/api-check/android-test-base-27-api/src/java/android/signature/cts/api/api27/test/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.api27.test;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
diff --git a/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
index c5ecdbd..85e7484 100644
--- a/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
@@ -30,7 +30,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.android_test_mock_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.current.mock.SignatureTest" />
         <option name="instrumentation-arg" key="expected-api-files" value="android-test-mock-current.api" />
         <option name="runtime-hint" value="5s" />
     </test>
diff --git a/tests/signature/api-check/android-test-mock-current-api/src/android/signature/cts/api/current/mock/SignatureTest.java b/tests/signature/api-check/android-test-mock-current-api/src/android/signature/cts/api/current/mock/SignatureTest.java
new file mode 100644
index 0000000..758188a
--- /dev/null
+++ b/tests/signature/api-check/android-test-mock-current-api/src/android/signature/cts/api/current/mock/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.current.mock;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
diff --git a/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
index 53bed33..703caf7 100644
--- a/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
@@ -33,7 +33,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.android_test_runner_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.current.runner.SignatureTest" />
         <option name="instrumentation-arg" key="expected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
         <option name="runtime-hint" value="5s" />
     </test>
diff --git a/tests/signature/api-check/android-test-runner-current-api/src/android/signature/cts/api/current/runner/SignatureTest.java b/tests/signature/api-check/android-test-runner-current-api/src/android/signature/cts/api/current/runner/SignatureTest.java
new file mode 100644
index 0000000..65f43ec
--- /dev/null
+++ b/tests/signature/api-check/android-test-runner-current-api/src/android/signature/cts/api/current/runner/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.current.runner;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
index 3bbc90e..6a33f1c 100644
--- a/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
@@ -33,7 +33,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.apache_http_legacy_27" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.api27.http.SignatureTest" />
         <option name="instrumentation-arg" key="base-api-files" value="current.api" />
         <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-minus-current.api" />
         <option name="runtime-hint" value="5s" />
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/src/android/signature/cts/api/api27/http/SignatureTest.java b/tests/signature/api-check/apache-http-legacy-27-api/src/android/signature/cts/api/api27/http/SignatureTest.java
new file mode 100644
index 0000000..7c14ec1
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-27-api/src/android/signature/cts/api/api27/http/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.api27.http;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
index 418c881..f204883 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
@@ -30,7 +30,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.apache_http_legacy_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.current.http.SignatureTest" />
         <option name="instrumentation-arg" key="unexpected-api-files" value="apache-http-legacy-minus-current.api" />
         <option name="runtime-hint" value="5s" />
     </test>
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/src/android/signature/cts/api/current/http/SignatureTest.java b/tests/signature/api-check/apache-http-legacy-current-api/src/android/signature/cts/api/current/http/SignatureTest.java
new file mode 100644
index 0000000..582e5da
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-current-api/src/android/signature/cts/api/current/http/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.current.http;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
index bd2c566..6fb7868 100644
--- a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
@@ -33,7 +33,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.apache_http_legacy_uses_library" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.http_uses_library.SignatureTest" />
         <option name="instrumentation-arg" key="base-api-files" value="current.api" />
         <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-minus-current.api" />
         <option name="runtime-hint" value="5s" />
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/src/android/signature/cts/api/http_uses_library/SignatureTest.java b/tests/signature/api-check/apache-http-legacy-uses-library-api/src/android/signature/cts/api/http_uses_library/SignatureTest.java
new file mode 100644
index 0000000..b8b94cf
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/src/android/signature/cts/api/http_uses_library/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.http_uses_library;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
diff --git a/tests/signature/api-check/build_signature_apk.mk b/tests/signature/api-check/build_signature_apk.mk
index b883d6a..4181827 100644
--- a/tests/signature/api-check/build_signature_apk.mk
+++ b/tests/signature/api-check/build_signature_apk.mk
@@ -74,6 +74,12 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
+ifneq (,$(wildcard $(LOCAL_PATH)/src))
+  LOCAL_SRC_FILES := $(call all-java-files-under, src)
+endif
+
 include $(BUILD_CTS_PACKAGE)
 
 LOCAL_SIGNATURE_API_FILES :=
diff --git a/tests/signature/api-check/current-api/AndroidTest.xml b/tests/signature/api-check/current-api/AndroidTest.xml
index 59b7bd6..8253275 100644
--- a/tests/signature/api-check/current-api/AndroidTest.xml
+++ b/tests/signature/api-check/current-api/AndroidTest.xml
@@ -37,7 +37,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.current.SignatureTest" />
         <option name="instrumentation-arg" key="expected-api-files" value="current.api" />
         <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
         <option name="runtime-hint" value="30s" />
diff --git a/tests/signature/api-check/current-api/src/android/signature/cts/api/current/SignatureTest.java b/tests/signature/api-check/current-api/src/android/signature/cts/api/current/SignatureTest.java
new file mode 100644
index 0000000..1eadd2f
--- /dev/null
+++ b/tests/signature/api-check/current-api/src/android/signature/cts/api/current/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.current;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
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 bf13b5a..4413824 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
@@ -30,7 +30,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_api_27" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.HiddenApiTest" />
+        <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="runtime-hint" value="30s" />
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/src/android/signature/cts/api/api27/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blacklist-27-api/src/android/signature/cts/api/api27/HiddenApiTest.java
new file mode 100644
index 0000000..c940aac
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/src/android/signature/cts/api/api27/HiddenApiTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.api27;
+
+public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest {
+}
diff --git a/tests/signature/api-check/hidden-api-blacklist-28/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-28/AndroidTest.xml
index 011a565..6bebfe1 100644
--- a/tests/signature/api-check/hidden-api-blacklist-28/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-28/AndroidTest.xml
@@ -30,7 +30,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_api_28" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.HiddenApiTest" />
+        <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="runtime-hint" value="30s" />
diff --git a/tests/signature/api-check/hidden-api-blacklist-28/src/android/signature/cts/api/api28/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blacklist-28/src/android/signature/cts/api/api28/HiddenApiTest.java
new file mode 100644
index 0000000..f85dda3
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-28/src/android/signature/cts/api/api28/HiddenApiTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.api28;
+
+public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest {
+}
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 ab5e735..6f14d96 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
@@ -30,7 +30,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.HiddenApiTest" />
+        <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="runtime-hint" value="30s" />
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/src/android/signature/cts/api/current/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blacklist-current-api/src/android/signature/cts/api/current/HiddenApiTest.java
new file mode 100644
index 0000000..34f33fe
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/src/android/signature/cts/api/current/HiddenApiTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.current;
+
+public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest {
+}
diff --git a/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk b/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
index 7423448..003eb7f 100644
--- a/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
+++ b/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
@@ -27,4 +27,6 @@
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk b/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
index 9364286..5dca9c1 100644
--- a/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
+++ b/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
@@ -27,4 +27,6 @@
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk b/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
index 2274762..ab0eef9 100644
--- a/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
+++ b/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
@@ -27,4 +27,6 @@
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/system-api/AndroidTest.xml b/tests/signature/api-check/system-api/AndroidTest.xml
index 5f70478..6504182 100644
--- a/tests/signature/api-check/system-api/AndroidTest.xml
+++ b/tests/signature/api-check/system-api/AndroidTest.xml
@@ -34,7 +34,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.api.system" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
-        <option name="class" value="android.signature.cts.api.SignatureTest" />
+        <option name="class" value="android.signature.cts.api.system.SignatureTest" />
         <option name="instrumentation-arg" key="base-api-files" value="current.api" />
         <option name="instrumentation-arg" key="expected-api-files" value="system-all.api.zip" />
         <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
diff --git a/tests/signature/api-check/system-api/src/android/signature/cts/api/system/SignatureTest.java b/tests/signature/api-check/system-api/src/android/signature/cts/api/system/SignatureTest.java
new file mode 100644
index 0000000..5316e31
--- /dev/null
+++ b/tests/signature/api-check/system-api/src/android/signature/cts/api/system/SignatureTest.java
@@ -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.
+ */
+
+package android.signature.cts.api.system;
+
+public class SignatureTest extends android.signature.cts.api.SignatureTest {
+}
diff --git a/tests/tests/animation/Android.bp b/tests/tests/animation/Android.bp
new file mode 100644
index 0000000..d5b1993
--- /dev/null
+++ b/tests/tests/animation/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2011 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: "CtsAnimationTestCases",
+    defaults: ["cts_defaults"],
+
+    static_libs: [
+        "android-support-test",
+        "mockito-target-minus-junit4",
+        "android-common",
+        "compatibility-device-util",
+        "ctstestrunner",
+        "platform-test-annotations",
+    ],
+
+    libs: ["android.test.runner.stubs"],
+
+    srcs: ["src/**/*.java"],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+
+    sdk_version: "test_current",
+}
diff --git a/tests/tests/animation/Android.mk b/tests/tests/animation/Android.mk
deleted file mode 100644
index 293f75f..0000000
--- a/tests/tests/animation/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2011 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 := CtsAnimationTestCases
-
-# 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 += \
-    android-support-test \
-    mockito-target-minus-junit4 \
-    android-common \
-    compatibility-device-util \
-    ctstestrunner \
-    platform-test-annotations
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-# Enforce public / test api only
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
index 655eb1c..ef2d35ac 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
@@ -18,7 +18,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -205,18 +204,23 @@
 
     @Test
     public void testNullObjectAnimator() throws Throwable {
-        Object object = mActivity.view.newBall;
-        final ObjectAnimator animator = ObjectAnimator.ofFloat(object, "y", 0, 100);
+        class AnimTarget {
+            public float y = 0f;
+            public void setY(float y) {
+                this.y = y;
+            }
+
+            public float getY() {
+                return y;
+            }
+        }
+        final ObjectAnimator animator = ObjectAnimator.ofFloat(new AnimTarget(), "y", 0, 100);
         MyListener listener = new MyListener();
         animator.addListener(listener);
-        mActivity.view.newBall.setY(0);
-        startAnimation(animator);
-        int sleepCount = 0;
-        while (mActivity.view.newBall.getY() == 0 && sleepCount++ < 50) {
-            SystemClock.sleep(1);
-        }
-        assertNotSame(0, mActivity.view.newBall.getY());
-        mActivityRule.runOnUiThread(() -> animator.setTarget(null));
+        mActivityRule.runOnUiThread(() -> {
+            animator.start();
+            animator.setTarget(null);
+        });
         assertTrue(listener.mCancel);
     }
 
diff --git a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
index 8650b7a..b0718fe 100644
--- a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
@@ -846,7 +846,7 @@
     public void testCachedValues() throws Throwable {
         final AnimTarget target = new AnimTarget();
         final ObjectAnimator anim = ObjectAnimator.ofFloat(target, "testValue", 100);
-        anim.setDuration(200);
+        anim.setDuration(100);
         final CountDownLatch twoFramesLatch = new CountDownLatch(2);
         mActivityRule.runOnUiThread(() -> {
             anim.start();
@@ -865,7 +865,7 @@
         });
 
         assertTrue("Animation didn't start in a reasonable time",
-                twoFramesLatch.await(200, TimeUnit.MILLISECONDS));
+                twoFramesLatch.await(800, TimeUnit.MILLISECONDS));
 
         mActivityRule.runOnUiThread(() -> {
             assertTrue("Start value should readjust to current position",
diff --git a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
index e7d939f..427237c 100644
--- a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
@@ -32,8 +32,10 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
 import android.animation.TypeEvaluator;
 import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.graphics.Color;
 import android.graphics.PointF;
 import android.os.SystemClock;
@@ -480,43 +482,76 @@
 
     @Test
     public void testGetAnimatedFraction() throws Throwable {
-        ValueAnimator objAnimator = getAnimator();
-        objAnimator.setRepeatCount(0);
-        startAnimation(objAnimator);
-        assertNotNull(objAnimator);
-        float[] fractions = getValue(objAnimator, 5, "getAnimatedFraction()", 100L, null);
-        for (int j = 0; j < fractions.length - 1; j++) {
-            assertTrue(fractions[j] >= 0.0);
-            assertTrue(fractions[j] <= 1.0);
-            assertTrue(errorMessage(fractions), fractions[j + 1] >= fractions[j]);
+        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+        assertNotNull(animator);
+        animator.setDuration(200);
+        animator.addUpdateListener(new AnimatorUpdateListener() {
+            public float lastFraction = 0;
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float currentFraction = animation.getAnimatedFraction();
+                assertTrue(
+                        "Last fraction = " + lastFraction + "current fraction = " + currentFraction,
+                        animation.getAnimatedFraction() >= lastFraction);
+                lastFraction = currentFraction;
+                assertTrue(currentFraction <= 1f);
+            }
+        });
+        CountDownLatch latch = new CountDownLatch(1);
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                latch.countDown();
+            }
+        });
+        mActivityRule.runOnUiThread(() -> {
+            animator.start();
+        });
+
+        latch.await(1000, TimeUnit.MILLISECONDS);
+
+        assertEquals(1.0f, animator.getAnimatedFraction(), EPSILON);
+    }
+
+    class TestInterpolator implements TimeInterpolator {
+
+        @Override
+        public float getInterpolation(float input) {
+            return input * input;
         }
     }
 
     @Test
-    public void testGetAnimatedValue() throws Throwable {
-        ValueAnimator objAnimator = getAnimator();
-        objAnimator.setRepeatCount(0);
-        startAnimation(objAnimator);
-        assertNotNull(objAnimator);
-        float[] animatedValues = getValue(objAnimator, 5, "getAnimatedValue()", 100L, null);
+    public void testGetAnimatedValue() {
+        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+        assertNotNull(animator);
+        TimeInterpolator myInterpolator = new TestInterpolator();
+        animator.setInterpolator(myInterpolator);
+        int sliceNum = 10;
+        for (int i = 0; i <= sliceNum; i++) {
+            float fraction = i / (float) sliceNum;
+            animator.setCurrentFraction(fraction);
+            assertEquals(myInterpolator.getInterpolation(fraction),
+                    (float) animator.getAnimatedValue(), EPSILON);
 
-        for (int j = 0; j < animatedValues.length - 1; j++) {
-            assertTrue(errorMessage(animatedValues), animatedValues[j + 1] >= animatedValues[j]);
         }
     }
 
     @Test
-    public void testGetAnimatedValue_PropertyName() throws Throwable {
-        String property = "y";
+    public void testGetAnimatedValue_PropertyName() {
+        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 100f, -100f);
+        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 0f, 1f);
+        ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(pvhX, pvhY);
+        assertNotNull(animator);
+        TimeInterpolator myInterpolator = new TestInterpolator();
+        animator.setInterpolator(myInterpolator);
+        int sliceNum = 10;
+        for (int i = 0; i <= sliceNum; i++) {
+            float fraction = i / (float) sliceNum;
+            animator.setCurrentFraction(fraction);
+            assertEquals(myInterpolator.getInterpolation(fraction),
+                    (float) animator.getAnimatedValue("y"), EPSILON);
 
-        ValueAnimator objAnimator = getAnimator();
-        objAnimator.setRepeatCount(0);
-        startAnimation(objAnimator);
-        assertNotNull(objAnimator);
-        float[] animatedValues = getValue(objAnimator, 5, "getAnimatedValue(property)", 100L,
-            property);
-        for (int j = 0; j < animatedValues.length - 1; j++) {
-            assertTrue(errorMessage(animatedValues), animatedValues[j + 1] >= animatedValues[j]);
         }
     }
 
@@ -703,24 +738,6 @@
         return objAnimator;
     }
 
-    private float[] getValue(ValueAnimator animator, int n, String methodName,
-            long sleepTime, String property) throws InterruptedException {
-        float[] values = new float[n];
-        for(int i = 0; i < n; i++){
-            SystemClock.sleep(sleepTime);
-            float value = 0.0f;
-            if(methodName.equals("getAnimatedFraction()")) {
-                value = animator.getAnimatedFraction();
-            }else if(methodName.equals("getAnimatedValue()")) {
-              value = ((Float)animator.getAnimatedValue()).floatValue();
-            }else if(methodName.equals("getAnimatedValue(property)")) {
-              value = ((Float)animator.getAnimatedValue(property)).floatValue();
-            }
-            values[i] = value;
-        }
-        return values;
-    }
-
     private void startAnimation(final ValueAnimator animator) throws Throwable {
         mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator));
     }
diff --git a/tests/tests/appwidget/AndroidTest.xml b/tests/tests/appwidget/AndroidTest.xml
index 4b19277..8b193fb 100644
--- a/tests/tests/appwidget/AndroidTest.xml
+++ b/tests/tests/appwidget/AndroidTest.xml
@@ -16,6 +16,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="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="CtsAppWidgetLauncher1.apk" />
diff --git a/tests/tests/background/AndroidTest.xml b/tests/tests/background/AndroidTest.xml
index f0af389..364457e 100644
--- a/tests/tests/background/AndroidTest.xml
+++ b/tests/tests/background/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="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" />
diff --git a/tests/tests/binder_ndk/AndroidManifest.xml b/tests/tests/binder_ndk/AndroidManifest.xml
index d4ab466..8be6801 100644
--- a/tests/tests/binder_ndk/AndroidManifest.xml
+++ b/tests/tests/binder_ndk/AndroidManifest.xml
@@ -15,7 +15,8 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.binder.cts">
+    package="android.binder.cts"
+    android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application android:debuggable="true">
diff --git a/tests/tests/carrierapi/AndroidTest.xml b/tests/tests/carrierapi/AndroidTest.xml
index d77f373..2f445eb 100644
--- a/tests/tests/carrierapi/AndroidTest.xml
+++ b/tests/tests/carrierapi/AndroidTest.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Carrier APIs test cases">
-    <option name="test-suite-tag" value="cts" />
+  <option name="test-suite-tag" value="cts" />
+    <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="component" value="telecom" />
     <option name="config-descriptor:metadata" key="token" value="UICC_SIM_CARD" />
     <option name="not-shardable" value="true" />
diff --git a/tests/tests/contactsproviderwipe/AndroidTest.xml b/tests/tests/contactsproviderwipe/AndroidTest.xml
index 7bbb519..d73a717 100644
--- a/tests/tests/contactsproviderwipe/AndroidTest.xml
+++ b/tests/tests/contactsproviderwipe/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <!-- 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="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 969ee21..3ceb414 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -30,7 +30,6 @@
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Telephony;
-import android.speech.RecognizerIntent;
 import android.telecom.TelecomManager;
 import android.test.AndroidTestCase;
 
@@ -343,6 +342,13 @@
         }
     }
 
+    public void testUsageAccessSettings() {
+        PackageManager packageManager = mContext.getPackageManager();
+        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            assertCanBeHandled(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
+        }
+    }
+
     public void testPictureInPictureSettings() {
         PackageManager packageManager = mContext.getPackageManager();
         if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
diff --git a/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java b/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java
index 77250f8..c72d8b3 100644
--- a/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java
@@ -127,6 +127,15 @@
         }
     }
 
+    @Test
+    public void testGetAppUsageLimit_allowsZeroLimit() {
+        registerObserver(DEFAULT_OBSERVER_ID, 0);
+        final LauncherApps.AppUsageLimit limit = mLauncherApps.getAppUsageLimit(
+                SETTINGS_PACKAGE, USER_HANDLE);
+        assertNotNull("An observer with a time limit of 0 was not registered.", limit);
+        assertEquals("Usage remaining expected to be 0.", 0, limit.getUsageRemaining());
+    }
+
     @After
     public void tearDown() throws Exception {
         unregisterObserver(DEFAULT_OBSERVER_ID);
diff --git a/tests/tests/dynamic_linker/AndroidManifest.xml b/tests/tests/dynamic_linker/AndroidManifest.xml
index 7a9166d..6a3a270 100644
--- a/tests/tests/dynamic_linker/AndroidManifest.xml
+++ b/tests/tests/dynamic_linker/AndroidManifest.xml
@@ -15,7 +15,8 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.dynamiclinker">
+    package="com.android.dynamiclinker"
+    android:targetSandboxVersion="2">
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -23,4 +24,4 @@
     <instrumentation
         android:targetPackage="com.android.dynamiclinker"
         android:name="android.support.test.runner.AndroidJUnitRunner" />
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tests/tests/dynamic_linker/AndroidTest.xml b/tests/tests/dynamic_linker/AndroidTest.xml
index e4fa4cb..58fe8a0 100644
--- a/tests/tests/dynamic_linker/AndroidTest.xml
+++ b/tests/tests/dynamic_linker/AndroidTest.xml
@@ -16,7 +16,7 @@
 <configuration description="Config for CTS dynamic linker test cases">
     <option name="test-suite-tag" value="cts" />
     <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="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" />
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index 76552a1..659c56d 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.graphics.cts">
+        package="android.graphics.cts"
+        android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
diff --git a/tests/tests/graphics/AndroidTest.xml b/tests/tests/graphics/AndroidTest.xml
index f6eb47f..0c99b6a 100644
--- a/tests/tests/graphics/AndroidTest.xml
+++ b/tests/tests/graphics/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS Graphics test cases">
     <option name="test-suite-tag" value="cts" />
     <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" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsGraphicsTestCases.apk" />
diff --git a/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java b/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java
new file mode 100644
index 0000000..04d2d35
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright 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.
+ */
+
+package android.graphics.cts;
+
+import static org.junit.Assert.assertEquals;
+//import static android.opengl.EGL14.*;
+//import static android.opengl.EGL15.*;
+
+import android.opengl.EGL14;
+import android.opengl.EGL15;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLImage;
+import android.opengl.EGLSurface;
+import android.opengl.EGLSync;
+import android.opengl.GLES20;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+
+@SmallTest
+@RunWith(BlockJUnit4ClassRunner.class)
+public class EGL15Test {
+
+    static {
+        System.loadLibrary("ctsgraphics_jni");
+    }
+
+    private static final String TAG = EGL15Test.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private EGLDisplay mEglDisplay = EGL15.EGL_NO_DISPLAY;
+    private EGLConfig mEglConfig = null;
+    private EGLSurface mEglPbuffer = EGL15.EGL_NO_SURFACE;
+    private EGLContext mEglContext = EGL15.EGL_NO_CONTEXT;
+    private int mEglVersion = 0;
+
+    @Before
+    public void setup() throws Throwable {
+        int error;
+
+        mEglDisplay = EGL15.eglGetPlatformDisplay(EGL15.EGL_PLATFORM_ANDROID_KHR,
+                EGL14.EGL_DEFAULT_DISPLAY,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (mEglDisplay == EGL15.EGL_NO_DISPLAY) {
+            throw new RuntimeException("no EGL display");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglGetPlatformDisplay failed");
+        }
+
+        int[] major = new int[1];
+        int[] minor = new int[1];
+        if (!EGL14.eglInitialize(mEglDisplay, major, 0, minor, 0)) {
+            throw new RuntimeException("error in eglInitialize");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglInitialize failed");
+        }
+        mEglVersion = major[0] * 10 + minor[0];
+
+        // If we could rely on having EGL_KHR_surfaceless_context and EGL_KHR_context_no_config, we
+        // wouldn't have to create a config or pbuffer at all.
+
+        int[] numConfigs = new int[1];
+        EGLConfig[] configs = new EGLConfig[1];
+        if (!EGL14.eglChooseConfig(mEglDisplay,
+                new int[] {
+                    EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+                    EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
+                    EGL14.EGL_NONE},
+                0, configs, 0, 1, numConfigs, 0)) {
+            throw new RuntimeException("eglChooseConfig failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglChooseConfig failed");
+        }
+
+        mEglConfig = configs[0];
+
+        mEglPbuffer = EGL14.eglCreatePbufferSurface(mEglDisplay, mEglConfig,
+                new int[] {EGL14.EGL_WIDTH, 1, EGL14.EGL_HEIGHT, 1, EGL14.EGL_NONE}, 0);
+        if (mEglPbuffer == EGL15.EGL_NO_SURFACE) {
+            throw new RuntimeException("eglCreatePbufferSurface failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreatePbufferSurface failed");
+        }
+
+
+        mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL14.EGL_NO_CONTEXT,
+                new int[] {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}, 0);
+        if (mEglContext == EGL15.EGL_NO_CONTEXT) {
+            throw new RuntimeException("eglCreateContext failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateContext failed");
+        }
+
+
+        if (!EGL14.eglMakeCurrent(mEglDisplay, mEglPbuffer, mEglPbuffer, mEglContext)) {
+            throw new RuntimeException("eglMakeCurrent failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglMakeCurrent failed");
+        }
+    }
+
+    @After
+    public void teardown() throws Throwable {
+        EGL14.eglTerminate(mEglDisplay);
+    }
+
+    @Test
+    public void testEGL15SyncFence() {
+        if (mEglVersion < 15) {
+            return;
+        }
+        EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (sync == EGL15.EGL_NO_SYNC) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+        int error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+
+        GLES20.glFlush();
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glFlush failed");
+        }
+
+        int status = EGL15.eglClientWaitSync(mEglDisplay, sync, 0, EGL15.EGL_FOREVER);
+        if (status != EGL15.EGL_CONDITION_SATISFIED) {
+            throw new RuntimeException("eglClientWaitSync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglClientWaitSync failed");
+        }
+
+        if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+    }
+
+    @Test
+    public void testEGL15GetSyncType() {
+        if (mEglVersion < 15) {
+            return;
+        }
+        EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (sync == EGL15.EGL_NO_SYNC) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+        int error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+
+        long[] type = new long[1];
+        boolean success = EGL15.eglGetSyncAttrib(mEglDisplay, sync, EGL15.EGL_SYNC_TYPE, type, 0);
+        if (!success) {
+            throw new RuntimeException("eglGetSyncAttrib failed (returned false)");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglGetSyncAttrib failed");
+        }
+        assertEquals(type[0], EGL15.EGL_SYNC_FENCE);
+
+        if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+    }
+
+    @Test
+    public void testEGL15WaitSync() {
+        if (mEglVersion < 15) {
+            return;
+        }
+        EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (sync == EGL15.EGL_NO_SYNC) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+        int error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+
+        boolean success = EGL15.eglWaitSync(mEglDisplay, sync, 0);
+        if (!success) {
+            throw new RuntimeException("eglWaitSync failed (returned false)");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglWaitSync failed");
+        }
+
+        if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+    }
+
+    @Test
+    public void testEGL15CreateImage() {
+        if (mEglVersion < 15) {
+            return;
+        }
+
+        int error;
+        int srcTex = 1;
+        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, srcTex);
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glBindTexture failed");
+        }
+
+        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 64, 64, 0,
+                            GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glTexImage2D failed");
+        }
+
+        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
+                               GLES20.GL_LINEAR);
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glTexParameteri failed");
+        }
+
+        long[] attribs = new long[] {
+                EGL15.EGL_GL_TEXTURE_LEVEL, 0,
+                EGL14.EGL_NONE };
+        EGLImage image = EGL15.eglCreateImage(mEglDisplay, mEglContext,
+                EGL15.EGL_GL_TEXTURE_2D, srcTex, attribs, 0);
+        if (image == EGL15.EGL_NO_IMAGE) {
+            throw new RuntimeException("eglCreateImage failed, got EGL_NO_IMAGE");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateImage failed");
+        }
+
+        boolean success = EGL15.eglDestroyImage(mEglDisplay, image);
+        if (!success) {
+            throw new RuntimeException("eglDestroyImage failed (returned false)");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroyImage failed");
+        }
+    }
+
+    @Test
+    public void testEGL15CreatePlatformPixmap() {
+        if (mEglVersion < 15) {
+            return;
+        }
+
+        long[] attribs = new long[] { EGL14.EGL_NONE };
+        boolean unsupported = false;
+        try {
+            EGLSurface surface = EGL15.eglCreatePlatformPixmapSurface(mEglDisplay,
+                    mEglConfig, null, attribs, 0);
+        } catch (UnsupportedOperationException e) {
+            unsupported = true;
+        }
+        if (!unsupported) {
+            throw new RuntimeException("eglCreatePlatformPixmapSurface is not supported on Android,"
+                    + " why did call not report that!");
+        }
+    }
+}
+
+// Note: Need to add tests for eglCreatePlatformWindowSurface
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java
index 7487e55..5218a4fd 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java
@@ -18,15 +18,21 @@
 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.assertTrue;
 
+import android.R;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.LightingColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.ColorStateListDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -78,6 +84,15 @@
     }
 
     @Test
+    public void testHasFocusStateSpecified() {
+        assertFalse(mDrawable.hasFocusStateSpecified());
+        final int[][] state = new int[][]{new int[]{1}, new int[]{2, R.attr.state_focused}};
+        final int[] colors = new int[]{Color.MAGENTA, Color.CYAN};
+        mDrawable.setColorStateList(new ColorStateList(state, colors));
+        assertTrue(mDrawable.hasFocusStateSpecified());
+    }
+
+    @Test
     public void testAlpha() {
         int transBlue = (Color.BLUE & 0xFFFFFF) | 127 << 24;
         mDrawable.setColorStateList(ColorStateList.valueOf(transBlue));
@@ -99,6 +114,31 @@
     }
 
     @Test
+    public void testColorFilter() {
+        final ColorDrawable colorDrawable = (ColorDrawable) mDrawable.getCurrent();
+        final ColorFilter colorFilter = new LightingColorFilter(Color.GRAY, Color.GREEN);
+
+        assertNull(mDrawable.getColorFilter());
+        mDrawable.setColorFilter(colorFilter);
+        assertEquals(colorFilter, mDrawable.getColorFilter());
+    }
+
+    @Test
+    public void testColorStateListAccess() {
+        final ColorStateListDrawable cslDrawable = new ColorStateListDrawable();
+        final ColorDrawable colorDrawable = (ColorDrawable) cslDrawable.getCurrent();
+        assertNotNull(cslDrawable.getColorStateList());
+        assertEquals(
+                colorDrawable.getColor(),
+                cslDrawable
+                        .getColorStateList()
+                        .getColorForState(cslDrawable.getState(), Color.YELLOW));
+
+        cslDrawable.setColorStateList(mColorStateList);
+        assertEquals(mColorStateList, cslDrawable.getColorStateList());
+    }
+
+    @Test
     public void testSetState() {
         ColorDrawable colorDrawable = (ColorDrawable) mDrawable.getCurrent();
         assertEquals(colorDrawable.getColor(), mColorStateList.getDefaultColor());
@@ -114,4 +154,79 @@
         assertEquals(mDrawable.mutate(), mDrawable);
         assertNotEquals(mDrawable.getConstantState(), oldState);
     }
+
+    @Test
+    public void testInvalidationCallbackProxy() {
+        final TestCallback callback = new TestCallback();
+        mDrawable.setCallback(callback);
+
+        callback.mInvalidatedDrawable = null;
+        mDrawable.invalidateSelf();
+        assertEquals(mDrawable, callback.mInvalidatedDrawable);
+
+        callback.mInvalidatedDrawable = null;
+        mDrawable.getCurrent().invalidateSelf();
+        assertEquals(mDrawable, callback.mInvalidatedDrawable);
+    }
+
+    @Test
+    public void testScheduleCallbackProxy() {
+        final Runnable runnable = new NoOpRunnable();
+        final long scheduledTime = SystemClock.uptimeMillis() + 100;
+        final TestCallback callback = new TestCallback();
+        mDrawable.setCallback(callback);
+
+        mDrawable.getCurrent().scheduleSelf(runnable, scheduledTime);
+        assertEquals(mDrawable, callback.mScheduledDrawable);
+        assertEquals(runnable, callback.mScheduledRunnable);
+        assertEquals(scheduledTime, callback.mScheduledTime);
+    }
+
+    @Test
+    public void testUnscheduleCallbackProxy() {
+        final Runnable runnable = new NoOpRunnable();
+        final TestCallback callback = new TestCallback();
+        mDrawable.setCallback(callback);
+
+        mDrawable.getCurrent().unscheduleSelf(runnable);
+
+        assertEquals(mDrawable, callback.mUnscheduledDrawable);
+        assertEquals(runnable, callback.mUnscheduledRunnable);
+    }
+
+    private final class TestCallback implements Drawable.Callback {
+        private Drawable mInvalidatedDrawable;
+        private Drawable mScheduledDrawable;
+        private Drawable mUnscheduledDrawable;
+
+        private Runnable mScheduledRunnable;
+        private Runnable mUnscheduledRunnable;
+
+        private long mScheduledTime;
+
+        @Override
+        public void invalidateDrawable(Drawable who) {
+            mInvalidatedDrawable = who;
+        }
+
+        @Override
+        public void scheduleDrawable(Drawable who, Runnable what, long when) {
+            mScheduledDrawable = who;
+            mScheduledRunnable = what;
+            mScheduledTime = when;
+        }
+
+        @Override
+        public void unscheduleDrawable(Drawable who, Runnable what) {
+            mUnscheduledDrawable = who;
+            mUnscheduledRunnable = what;
+        }
+    }
+
+    private final class NoOpRunnable implements Runnable {
+        @Override
+        public void run() {
+
+        }
+    }
 }
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index f0ebe63..7de8b1e 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -46,6 +46,8 @@
 LOCAL_SDK_VERSION := current
 LOCAL_NDK_STL_VARIANT := c++_shared
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_CTS_PACKAGE)
 
 # Include the associated library's makefile.
diff --git a/tests/tests/jni/AndroidManifest.xml b/tests/tests/jni/AndroidManifest.xml
index 18ef4c6..9321330 100644
--- a/tests/tests/jni/AndroidManifest.xml
+++ b/tests/tests/jni/AndroidManifest.xml
@@ -15,7 +15,8 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.jni.cts">
+    package="android.jni.cts"
+    android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application android:extractNativeLibs="true">
diff --git a/tests/tests/jni/TEST_MAPPING b/tests/tests/jni/TEST_MAPPING
new file mode 100644
index 0000000..5d9eea5
--- /dev/null
+++ b/tests/tests/jni/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsJniTestCases"
+    }
+  ]
+}
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index c00ae3b..0228f6e 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include <queue>
+#include <regex>
 #include <string>
 #include <unordered_set>
 #include <vector>
@@ -39,37 +40,44 @@
 #include <nativehelper/ScopedUtfChars.h>
 
 #if defined(__LP64__)
-static const std::string kSystemLibraryPath = "/system/lib64";
-static const std::string kVendorLibraryPath = "/vendor/lib64";
-static const std::string kProductLibraryPath = "/product/lib64";
+#define LIB_DIR "lib64"
 #else
-static const std::string kSystemLibraryPath = "/system/lib";
-static const std::string kVendorLibraryPath = "/vendor/lib";
-static const std::string kProductLibraryPath = "/product/lib";
+#define LIB_DIR "lib"
 #endif
 
+static const std::string kSystemLibraryPath = "/system/" LIB_DIR;
+static const std::string kRuntimeApexLibraryPath = "/apex/com.android.runtime/" LIB_DIR;
+static const std::string kVendorLibraryPath = "/vendor/" LIB_DIR;
+static const std::string kProductLibraryPath = "/product/" LIB_DIR;
+
+static const std::vector<std::regex> kSystemPathRegexes = {
+    std::regex("/system/lib(64)?"),
+    std::regex("/apex/com\\.android\\.[^/]*/lib(64)?"),
+};
+
 static const std::string kWebViewPlatSupportLib = "libwebviewchromium_plat_support.so";
 
-// This is not the complete list - just a small subset
-// of the libraries that should reside in /system/lib
-// for app-compatibility reasons.
-// (in addition to kSystemPublicLibraries)
+// This is not the complete list - just a small subset of the libraries that
+// should not be loaded from vendor locations.
+//
+// TODO(b/124049505): Do not hardcode expected paths here, to allow libraries to
+// migrate between /system and APEXes.
 static std::vector<std::string> kSystemLibraries = {
-    "libart.so",
-    "libandroid_runtime.so",
-    "libbinder.so",
-    "libcrypto.so",
-    "libcutils.so",
-    "libexpat.so",
-    "libgui.so",
-    "libmedia.so",
-    "libnativehelper.so",
-    "libstagefright.so",
-    "libsqlite.so",
-    "libui.so",
-    "libutils.so",
-    "libvorbisidec.so",
-  };
+    kRuntimeApexLibraryPath + "/libart.so",
+    kRuntimeApexLibraryPath + "/libnativehelper.so",
+    kSystemLibraryPath + "/libandroid_runtime.so",
+    kSystemLibraryPath + "/libbinder.so",
+    kSystemLibraryPath + "/libcrypto.so",
+    kSystemLibraryPath + "/libcutils.so",
+    kSystemLibraryPath + "/libexpat.so",
+    kSystemLibraryPath + "/libgui.so",
+    kSystemLibraryPath + "/libmedia.so",
+    kSystemLibraryPath + "/libsqlite.so",
+    kSystemLibraryPath + "/libstagefright.so",
+    kSystemLibraryPath + "/libui.so",
+    kSystemLibraryPath + "/libutils.so",
+    kSystemLibraryPath + "/libvorbisidec.so",
+};
 
 static bool is_directory(const char* path) {
   struct stat sb;
@@ -107,7 +115,8 @@
 
 // Tests if a file can be loaded or not. Returns empty string on success. On any failure
 // returns the error message from dlerror().
-static std::string load_library(JNIEnv* env, jclass clazz, const std::string& path) {
+static std::string load_library(JNIEnv* env, jclass clazz, const std::string& path,
+                                bool test_system_load_library) {
   // try to load the lib using dlopen().
   void *handle = dlopen(path.c_str(), RTLD_NOW);
   std::string error;
@@ -127,16 +136,40 @@
 
   // try to load the same lib using System.load() in Java to see if it gives consistent
   // result with dlopen.
-  static jmethodID load_library = env->GetStaticMethodID(clazz, "loadSharedLibrary",
-                                            "(Ljava/lang/String;)Z");
-  jstring jpath = env->NewStringUTF(path.c_str());
-  bool loaded_in_java = env->CallStaticBooleanMethod(clazz, load_library, jpath) == JNI_TRUE;
-  env->DeleteLocalRef(jpath);
-  if (loaded_in_native != loaded_in_java) {
-    error = "Inconsistent result for library \"" + path + "\":" +
-                      " dlopen() was " + (loaded_in_native ? "success" : "failure") +
-                      ", System.loadLibrary() was " + (loaded_in_java ? "success" : "failure");
-  } else if (loaded_in_java) {
+  static jmethodID java_load =
+      env->GetStaticMethodID(clazz, "loadWithSystemLoad", "(Ljava/lang/String;)Ljava/lang/String;");
+  ScopedLocalRef<jstring> jpath(env, env->NewStringUTF(path.c_str()));
+  jstring java_load_errmsg = jstring(env->CallStaticObjectMethod(clazz, java_load, jpath.get()));
+  bool java_load_ok = env->GetStringLength(java_load_errmsg) == 0;
+
+  jstring java_load_lib_errmsg;
+  bool java_load_lib_ok = java_load_ok;
+  if (test_system_load_library && java_load_ok) {
+    // If System.load() works then test System.loadLibrary() too. Cannot test
+    // the other way around since System.loadLibrary() might very well find the
+    // library somewhere else and hence work when System.load() fails.
+    std::string baselib = basename(path.c_str());
+    ScopedLocalRef<jstring> jname(env, env->NewStringUTF(baselib.c_str()));
+    static jmethodID java_load_lib = env->GetStaticMethodID(
+        clazz, "loadWithSystemLoadLibrary", "(Ljava/lang/String;)Ljava/lang/String;");
+    java_load_lib_errmsg = jstring(env->CallStaticObjectMethod(clazz, java_load_lib, jname.get()));
+    java_load_lib_ok = env->GetStringLength(java_load_lib_errmsg) == 0;
+  }
+
+  if (loaded_in_native != java_load_ok || java_load_ok != java_load_lib_ok) {
+    const std::string java_load_error(ScopedUtfChars(env, java_load_errmsg).c_str());
+    error = "Inconsistent result for library \"" + path + "\": dlopen() " +
+            (loaded_in_native ? "succeeded" : "failed (" + error + ")") +
+            ", System.load() " +
+            (java_load_ok ? "succeeded" : "failed (" + java_load_error + ")");
+    if (test_system_load_library) {
+      const std::string java_load_lib_error(ScopedUtfChars(env, java_load_lib_errmsg).c_str());
+      error += ", System.loadLibrary() " +
+               (java_load_lib_ok ? "succeeded" : "failed (" + java_load_lib_error + ")");
+    }
+  }
+
+  if (loaded_in_native && java_load_ok) {
     // Unload the shared lib loaded in Java. Since we don't have a method in Java for unloading a
     // lib other than destroying the classloader, here comes a trick; we open the same library
     // again with dlopen to get the handle for the lib and then calls dlclose twice (since we have
@@ -144,7 +177,7 @@
     // the same handle for the same shared lib object.
     handle = dlopen(path.c_str(), RTLD_NOW);
     dlclose(handle);
-    dlclose(handle); // don't delete this line. it's not a mistake.
+    dlclose(handle); // don't delete this line. it's not a mistake (see comment above).
   }
 
   return error;
@@ -156,7 +189,7 @@
                       const std::unordered_set<std::string>& library_search_paths,
                       const std::unordered_set<std::string>& libraries,
                       std::vector<std::string>* errors) {
-  std::string err = load_library(env, clazz, path);
+  std::string err = load_library(env, clazz, path, /*test_system_load_library=*/true);
   bool loaded = err.empty();
 
   // The current restrictions on public libraries:
@@ -329,33 +362,38 @@
 
   std::vector<std::string> library_search_paths = android::base::Split(default_search_paths, ":");
 
-  // Remove everything pointing outside of /system/lib*
+  // Remove everything pointing outside of /system/lib* and
+  // /apex/com.android.*/lib*.
   std::unordered_set<std::string> system_library_search_paths;
 
   for (const auto& path : library_search_paths) {
-    if (android::base::StartsWith(path, "/system/lib")) {
-      system_library_search_paths.insert(path);
+    for (const auto& regex : kSystemPathRegexes) {
+      if (std::regex_match(path, regex)) {
+        system_library_search_paths.insert(path);
+        break;
+      }
     }
   }
 
-  // This path should be tested too - this is because apps may rely on some
-  // libraries being available in /system/${LIB}/
+  // These paths should be tested too - this is because apps may rely on some
+  // libraries being available there.
   system_library_search_paths.insert(kSystemLibraryPath);
+  system_library_search_paths.insert(kRuntimeApexLibraryPath);
 
   if (!check_path(env, clazz, kSystemLibraryPath, system_library_search_paths,
                   system_public_libraries, &errors)) {
     success = false;
   }
 
-  // Check that the mandatory system libraries are present - the grey list
-  for (const auto& name : kSystemLibraries) {
-    std::string library = kSystemLibraryPath + "/" + name;
-    std::string err = load_library(env, clazz, library);
+  // Check that the mandatory system + APEX libraries are present - the grey list
+  for (const auto& library : kSystemLibraries) {
+    std::string err = load_library(env, clazz, library, /*test_system_load_library=*/false);
     if (!err.empty()) {
       // The libraries should be present and produce specific dlerror when inaccessible.
       if (!not_accessible(err)) {
-          errors.push_back("Mandatory system library \"" + library + "\" failed to load with unexpected error: " + err);
-          success = false;
+        errors.push_back("Mandatory system library \"" + library +
+                         "\" failed to load with unexpected error: " + err);
+        success = false;
       }
     }
   }
@@ -384,4 +422,3 @@
 
   return nullptr;
 }
-
diff --git a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
index 59f6cb1..634350f 100644
--- a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
+++ b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
@@ -226,26 +226,39 @@
         return nativePath;
     }
 
-    private static boolean loadSharedLibrary(String libFilePath) {
+    private static boolean isAlreadyOpenedError(UnsatisfiedLinkError e, String libFilePath) {
+        // If one of the public system libraries are already opened in the bootclassloader, consider
+        // this try as success, because dlopen to the lib is successful.
         String baseName = new File(libFilePath).getName();
+        return e.getMessage().contains("Shared library \"" + libFilePath +
+            "\" already opened by ClassLoader") &&
+            Arrays.asList(PUBLIC_SYSTEM_LIBRARIES).contains(baseName);
+    }
+
+    private static String loadWithSystemLoad(String libFilePath) {
         try {
             System.load(libFilePath);
-            // Also ensure that the lib is also accessible via its libname.
-            // Drop 'lib' and '.so' from the name
-            System.loadLibrary(baseName.substring(3, baseName.length()-3));
-            return true;
         } catch (UnsatisfiedLinkError e) {
             // all other exceptions are just thrown
-            if (e.getMessage().contains("Shared library \"" + libFilePath +
-                    "\" already opened by ClassLoader") &&
-                    Arrays.asList(PUBLIC_SYSTEM_LIBRARIES).contains(baseName)) {
-                // If one of the public system libraries are already opened in the
-                // bootclassloader, consider this try as success, because dlopen to the lib
-                // is successful.
-                return true;
+            if (!isAlreadyOpenedError(e, libFilePath)) {
+                return "System.load() UnsatisfiedLinkError: " + e.getMessage();
             }
-            return false;
         }
+        return "";
+    }
+
+    private static String loadWithSystemLoadLibrary(String libFileName) {
+        // Drop 'lib' and '.so' from the base name
+        String libName = libFileName.substring(3, libFileName.length()-3);
+        try {
+            System.loadLibrary(libName);
+        } catch (UnsatisfiedLinkError e) {
+            if (!isAlreadyOpenedError(e, libFileName)) {
+                return "System.loadLibrary(\"" + libName + "\") UnsatisfiedLinkError: " +
+                    e.getMessage();
+            }
+        }
+        return "";
     }
 
     // Verify the behaviour of native library loading in class loaders.
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
index 437948f..2ec15de 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
@@ -41,6 +41,7 @@
         measurement.setCarrierPhaseUncertainty(7.0);
         measurement.setCn0DbHz(8.0);
         measurement.setCodeType(GnssMeasurement.CODE_TYPE_C);
+        measurement.setOtherCodeTypeName("G");
         measurement.setConstellationType(GnssStatus.CONSTELLATION_GALILEO);
         measurement.setMultipathIndicator(GnssMeasurement.MULTIPATH_INDICATOR_DETECTED);
         measurement.setPseudorangeRateMetersPerSecond(9.0);
@@ -66,6 +67,7 @@
         assertEquals(GnssMeasurement.MULTIPATH_INDICATOR_DETECTED,
                 measurement.getMultipathIndicator());
         assertEquals(GnssMeasurement.CODE_TYPE_C, measurement.getCodeType());
+        assertEquals("G", measurement.getOtherCodeTypeName());
         assertEquals(9.0, measurement.getPseudorangeRateMetersPerSecond());
         assertEquals(10.0, measurement.getPseudorangeRateUncertaintyMetersPerSecond());
         assertEquals(11, measurement.getReceivedSvTimeNanos());
diff --git a/tests/tests/location/src/android/location/cts/GnssTestCase.java b/tests/tests/location/src/android/location/cts/GnssTestCase.java
index 62c38c8..a128c95 100644
--- a/tests/tests/location/src/android/location/cts/GnssTestCase.java
+++ b/tests/tests/location/src/android/location/cts/GnssTestCase.java
@@ -19,7 +19,6 @@
 import android.os.SystemProperties;
 import android.test.AndroidTestCase;
 import android.util.Log;
-import android.content.pm.PackageManager;
 
 /**
  * Base Test Case class for all Gnss Tests.
@@ -38,8 +37,7 @@
     // On devices using newer hardware, GNSS measurement support is required.
     protected boolean isMeasurementTestStrict() {
         // Enforce strict measurement test on devices with first API level at least P.
-        if (SystemProperties.getInt("ro.product.first_api_level", 0) >= Build.VERSION_CODES.P &&
-            !getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+        if (SystemProperties.getInt("ro.product.first_api_level", 0) >= Build.VERSION_CODES.P) {
             return true;
         }
 
diff --git a/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4 b/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
index 8820340..157c222 100644
--- a/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
+++ b/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/lg_g4_iso_800.jpg b/tests/tests/media/res/raw/lg_g4_iso_800.jpg
new file mode 100644
index 0000000..d264196
--- /dev/null
+++ b/tests/tests/media/res/raw/lg_g4_iso_800.jpg
Binary files differ
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index 3443f33..11c2efd 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -17,7 +17,7 @@
 <resources>
     <array name="exifbyteorderii_jpg">
         <item>true</item>
-        <item>3112</item>
+        <item>3500</item>
         <item>6265</item>
         <item>512</item>
         <item>288</item>
@@ -49,6 +49,9 @@
         <item>50</item>
         <item>6</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="exifbyteordermm_jpg">
         <item>false</item>
@@ -58,7 +61,7 @@
         <item>0</item>
         <item>false</item>
         <item>true</item>
-        <item>675</item>
+        <item>572</item>
         <item>24</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -84,6 +87,9 @@
         <item>146</item>
         <item>0</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="lg_g4_iso_800_dng">
         <item>true</item>
@@ -119,16 +125,57 @@
         <item>800</item>
         <item>1</item>
         <item>0</item>
+        <item>true</item>
+        <item>826</item>
+        <item>10067</item>
+    </array>
+    <array name="lg_g4_iso_800_jpg">
+        <item>false</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>true</item>
+        <item>1662</item>
+        <item>24</item>
+        <item>53.834507</item>
+        <item>10.69585</item>
+        <item>0.0</item>
+        <item>LGE</item>
+        <item>LG-H815</item>
+        <item>1.800</item>
+        <item>2015:11:12 16:46:18</item>
+        <item>0.0040</item>
+        <item>0.0</item>
+        <item>442/100</item>
+        <item />
+        <item />
+        <item>1970:01:17</item>
+        <item>53/1,50/1,423/100</item>
+        <item>N</item>
+        <item>10/1,41/1,4506/100</item>
+        <item>E</item>
+        <item />
+        <item>18:08:10</item>
+        <item>337</item>
+        <item>600</item>
+        <item>800</item>
+        <item>1</item>
+        <item>0</item>
+        <item>true</item>
+        <item>1809</item>
+        <item>13197</item>
     </array>
     <array name="volantis_jpg">
         <item>false</item>
         <item />
         <item />
-        <item>0</item>
-        <item>0</item>
-        <item>false</item>
+        <item />
+        <item />
+        <item />
         <item>true</item>
-        <item>3081</item>
+        <item>3143</item>
         <item>24</item>
         <item>37.423</item>
         <item>-122.162</item>
@@ -154,6 +201,9 @@
         <item>175</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="sony_rx_100_arw">
         <item>true</item>
@@ -189,6 +239,9 @@
         <item>125</item>
         <item>8</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="canon_g7x_cr2">
         <item>true</item>
@@ -224,6 +277,9 @@
         <item>12800</item>
         <item>8</item>
         <item>1</item>
+        <item>true</item>
+        <item>14336</item>
+        <item>8192</item>
     </array>
     <array name="fuji_x20_raf">
         <item>true</item>
@@ -259,6 +315,9 @@
         <item>100</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="nikon_1aw1_nef">
         <item>true</item>
@@ -294,6 +353,9 @@
         <item>200</item>
         <item>8</item>
         <item>0</item>
+        <item>true</item>
+        <item>472</item>
+        <item>2048</item>
     </array>
     <array name="nikon_p330_nrw">
         <item>true</item>
@@ -329,6 +391,9 @@
         <item>3200</item>
         <item>8</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="pentax_k5_pef">
         <item>true</item>
@@ -364,6 +429,9 @@
         <item>100</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="olympus_e_pl3_orf">
         <item>true</item>
@@ -399,6 +467,9 @@
         <item>200</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="panasonic_gm5_rw2">
         <item>true</item>
@@ -434,6 +505,9 @@
         <item>200</item>
         <item>8</item>
         <item>1</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="samsung_nx3000_srw">
         <item>true</item>
@@ -469,5 +543,8 @@
         <item>100</item>
         <item>8</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
 </resources>
diff --git a/tests/tests/media/src/android/media/cts/CodecUtils.java b/tests/tests/media/src/android/media/cts/CodecUtils.java
index ae785b2..15314ef 100644
--- a/tests/tests/media/src/android/media/cts/CodecUtils.java
+++ b/tests/tests/media/src/android/media/cts/CodecUtils.java
@@ -54,6 +54,8 @@
             for (int i = 0; i < planes.length; i++) {
                 mPlanes[i] = new PlaneWrapper(planes[i]);
             }
+
+            setCropRect(image.getCropRect());
         }
 
         public static ImageWrapper createFromImage(Image image) {
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
index 72eddf1..5704b70 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -1122,20 +1122,22 @@
 
         public void release() {
             looper.quit();
-            if (eglDisplay != EGL10.EGL_NO_DISPLAY) {
-                egl10.eglMakeCurrent(eglDisplay,
-                        EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
-                egl10.eglDestroySurface(eglDisplay, eglSurface);
-                egl10.eglDestroyContext(eglDisplay, eglContext);
-                egl10.eglTerminate(eglDisplay);
-            }
-            eglDisplay = EGL10.EGL_NO_DISPLAY;
-            eglContext = EGL10.EGL_NO_CONTEXT;
-            eglSurface = EGL10.EGL_NO_SURFACE;
             surface.release();
             surfaceTexture.release();
             byteBufferIsReady = false;
             byteBuffer =  null;
+            if (eglDisplay != EGL10.EGL_NO_DISPLAY) {
+                egl10.eglMakeCurrent(eglDisplay,
+                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+                egl10.eglDestroySurface(eglDisplay, eglSurface);
+                egl10.eglDestroyContext(eglDisplay, eglContext);
+                //TODO: uncomment following line after fixing crash in GL driver libGLESv2_adreno.so
+                //TODO: see b/123755902
+                //egl10.eglTerminate(eglDisplay);
+            }
+            eglDisplay = EGL10.EGL_NO_DISPLAY;
+            eglContext = EGL10.EGL_NO_CONTEXT;
+            eglSurface = EGL10.EGL_NO_SURFACE;
         }
 
         /* Makes our EGL context and surface current. */
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index 6301258..f1594af 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -277,6 +277,8 @@
             }
             mDecodingSurface = new OutputSurface(w, h);
             mDecoder.configure(decoderFormat, mDecodingSurface.getSurface(), null, 0);
+            // only scale to fit scaling mode is supported
+            mDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
             mDecoder.start();
             mDecoderInputBuffers = mDecoder.getInputBuffers();
 
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index 305a374..5bcfaa7 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -35,8 +35,11 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
 
 @AppModeFull(reason = "Instant apps cannot access the SD card")
 public class ExifInterfaceTest extends AndroidTestCase {
@@ -53,6 +56,7 @@
     private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
     private static final String EXIF_BYTE_ORDER_MM_JPEG = "image_exif_byte_order_mm.jpg";
     private static final String LG_G4_ISO_800_DNG = "lg_g4_iso_800.dng";
+    private static final String LG_G4_ISO_800_JPG = "lg_g4_iso_800.jpg";
     private static final String SONY_RX_100_ARW = "sony_rx_100.arw";
     private static final String CANON_G7X_CR2 = "canon_g7x.cr2";
     private static final String FUJI_X20_RAF = "fuji_x20.raf";
@@ -128,6 +132,11 @@
         public final int orientation;
         public final int whiteBalance;
 
+        // XMP information.
+        public final boolean hasXmp;
+        public final int xmpOffset;
+        public final int xmpLength;
+
         private static String getString(TypedArray typedArray, int index) {
             String stringValue = typedArray.getString(index);
             if (stringValue == null || stringValue.equals("")) {
@@ -178,6 +187,11 @@
             orientation = typedArray.getInt(index++, 0);
             whiteBalance = typedArray.getInt(index++, 0);
 
+            // Reads XMP information.
+            hasXmp = typedArray.getBoolean(index++, false);
+            xmpOffset = typedArray.getInt(index++, 0);
+            xmpLength = typedArray.getInt(index++, 0);
+
             typedArray.recycle();
         }
     }
@@ -254,6 +268,7 @@
         // Checks a thumbnail image.
         assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
         if (expectedValue.hasThumbnail) {
+            assertNotNull(exifInterface.getThumbnailRange());
             if (assertRanges) {
                 final long[] thumbnailRange = exifInterface.getThumbnailRange();
                 assertEquals(expectedValue.thumbnailOffset, thumbnailRange[0]);
@@ -268,6 +283,7 @@
             assertEquals(expectedValue.isThumbnailCompressed,
                     exifInterface.isThumbnailCompressed());
         } else {
+            assertNull(exifInterface.getThumbnailRange());
             assertNull(exifInterface.getThumbnail());
         }
 
@@ -275,6 +291,7 @@
         float[] latLong = new float[2];
         assertEquals(expectedValue.hasLatLong, exifInterface.getLatLong(latLong));
         if (expectedValue.hasLatLong) {
+            assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_GPS_LATITUDE));
             if (assertRanges) {
                 final long[] latitudeRange = exifInterface
                         .getAttributeRange(ExifInterface.TAG_GPS_LATITUDE);
@@ -286,6 +303,7 @@
             assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
             assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
         } else {
+            assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_GPS_LATITUDE));
             assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
             assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
         }
@@ -318,6 +336,26 @@
         assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
         assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
         assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
+
+        if (expectedValue.hasXmp) {
+            assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_XMP));
+            if (assertRanges) {
+                final long[] xmpRange = exifInterface.getAttributeRange(ExifInterface.TAG_XMP);
+                assertEquals(expectedValue.xmpOffset, xmpRange[0]);
+                assertEquals(expectedValue.xmpLength, xmpRange[1]);
+            }
+            final String xmp = new String(exifInterface.getAttributeBytes(ExifInterface.TAG_XMP),
+                    StandardCharsets.UTF_8);
+            // We're only interested in confirming that we were able to extract
+            // valid XMP data, which must always include this XML tag; a full
+            // XMP parser is beyond the scope of ExifInterface. See XMP
+            // Specification Part 1, Section C.2.2 for additional details.
+            if (!xmp.contains("<rdf:RDF")) {
+                fail("Invalid XMP: " + xmp);
+            }
+        } else {
+            assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_XMP));
+        }
     }
 
     private void testExifInterfaceCommon(String fileName, ExpectedValue expectedValue)
@@ -453,6 +491,12 @@
         testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
     }
 
+    public void testReadExifDataFromLgG4Iso800Jpg() throws Throwable {
+        stageFile(R.raw.lg_g4_iso_800, new File(Environment.getExternalStorageDirectory(),
+                EXTERNAL_BASE_DIRECTORY + LG_G4_ISO_800_JPG));
+        testExifInterfaceForJpeg(LG_G4_ISO_800_JPG, R.array.lg_g4_iso_800_jpg);
+    }
+
     public void testDoNotFailOnCorruptedImage() throws Throwable {
         // To keep the compatibility with old versions of ExifInterface, even on a corrupted image,
         // it shouldn't raise any exceptions except an IOException when unable to open a file.
@@ -535,4 +579,11 @@
         assertEquals(dateTimeOriginalValue, exif.getAttribute(ExifInterface.TAG_DATETIME));
         imageFile.delete();
     }
+
+    private void stageFile(int resId, File file) throws IOException {
+        try (InputStream source = getContext().getResources().openRawResource(resId);
+                OutputStream target = new FileOutputStream(file)) {
+            FileUtils.copy(source, target);
+        }
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index 648cf26..bd36a54 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -34,10 +34,14 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback;
+
 @SmallTest
 @RequiresDevice
 public class MediaCodecListTest extends AndroidTestCase {
@@ -188,7 +192,7 @@
             MediaCodec codec = MediaCodec.createByCodecName(info.getName());
 
             assertEquals(codec.getName(), info.getName());
-
+            assertEquals(codec.getCanonicalName(), info.getCanonicalName());
             assertEquals(codec.getCodecInfo(), info);
 
             codec.release();
@@ -452,6 +456,9 @@
                 CodecCapabilities cap = info.getCapabilitiesForType(types[j]);
                 AudioCapabilities audioCap = cap.getAudioCapabilities();
                 if (audioCap == null) {
+                    assertFalse("no audio capabilities for audio media type " + types[j] + " of "
+                                    + info.getName(),
+                                types[j].toLowerCase().startsWith("audio/"));
                     continue;
                 }
                 int n = audioCap.getMaxInputChannelCount();
@@ -460,4 +467,264 @@
             }
         }
     }
+
+    private void testCanonicalCodecIsNotAnAlias(String canonicalName) {
+        // canonical name must point to a non-alias
+        for (MediaCodecInfo canonical : mAllInfos) {
+            if (canonical.getName().equals(canonicalName)) {
+                assertFalse(canonical.isAlias());
+                return;
+            }
+        }
+        fail("could not find info to canonical name '" + canonicalName + "'");
+    }
+
+    private String getCustomPartOfComponentName(MediaCodecInfo info) {
+        String name = info.getName();
+        if (name.startsWith("OMX.") || name.startsWith("c2.")) {
+            // strip off OMX.<vendor_name>.
+            return name.replaceFirst("^OMX\\.([^.]+)\\.", "");
+        }
+        return name;
+    }
+
+    private void testKindInCodecNamesIsMeaningful(MediaCodecInfo info) {
+        String name = getCustomPartOfComponentName(info);
+        // codec names containing 'encoder' or 'enc' must be encoders, 'decoder' or 'dec' must
+        // be decoders
+        if (name.matches("(?i)\\b(encoder|enc)\\b")) {
+            assertTrue(info.isEncoder());
+        }
+        if (name.matches("(?i)\\b(decoder|dec)\\b")) {
+            assertFalse(info.isEncoder());
+        }
+    }
+
+    private void testMediaTypeInCodecNamesIsMeaningful(MediaCodecInfo info) {
+        // Codec names containing media type names must support that media type
+        String name = getCustomPartOfComponentName(info);
+
+        Set<String> supportedTypes = new HashSet<String>(Arrays.asList(info.getSupportedTypes()));
+
+        // video types
+        if (name.matches("(?i)\\b(mp(eg)?2)\\b")) {
+            // this may refer to audio mpeg1-layer2 or video mpeg2
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_MPEG2)
+                        || supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_MPEG + "-L2"));
+        }
+        if (name.matches("(?i)\\b(h\\.?263)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_H263));
+        }
+        if (name.matches("(?i)\\b(mp(eg)?4)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_MPEG4));
+        }
+        if (name.matches("(?i)\\b(h\\.?264|avc)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_AVC));
+        }
+        if (name.matches("(?i)\\b(vp8)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_VP8));
+        }
+        if (name.matches("(?i)\\b(h\\.?265|hevc)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_HEVC));
+        }
+        if (name.matches("(?i)\\b(vp9)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_VP9));
+        }
+        if (name.matches("(?i)\\b(av0?1)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_AV1));
+        }
+
+        // audio types
+        if (name.matches("(?i)\\b(mp(eg)?3)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_MPEG));
+        }
+        if (name.matches("(?i)\\b(x?aac)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_AAC));
+        }
+        if (name.matches("(?i)\\b(pcm)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_RAW));
+        }
+        if (name.matches("(?i)\\b(raw)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_RAW)
+                        || supportedTypes.contains(MediaFormat.MIMETYPE_VIDEO_RAW));
+        }
+        if (name.matches("(?i)\\b(amr)\\b")) {
+            if (name.matches("(?i)\\b(nb)\\b")) {
+                assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_AMR_NB));
+            } else if (name.matches("(?i)\\b(wb)\\b")) {
+                assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_AMR_WB));
+            } else {
+                assertTrue(
+                    supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
+                            || supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_AMR_WB));
+            }
+        }
+        if (name.matches("(?i)\\b(opus)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_OPUS));
+        }
+        if (name.matches("(?i)\\b(vorbis)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_VORBIS));
+        }
+        if (name.matches("(?i)\\b(flac)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_FLAC));
+        }
+        if (name.matches("(?i)\\b(ac3)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_AC3));
+        }
+        if (name.matches("(?i)\\b(ac4)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_AC4));
+        }
+        if (name.matches("(?i)\\b(eac3)\\b")) {
+            assertTrue(supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_EAC3)
+                        || supportedTypes.contains(MediaFormat.MIMETYPE_AUDIO_EAC3_JOC));
+        }
+    }
+
+    public void testCodecCharacterizations() {
+        for (MediaCodecInfo info : mAllInfos) {
+            Log.d(TAG, "codec: " + info.getName() + " canonical: " + info.getCanonicalName());
+
+            // AOSP codecs must not be marked as vendor or hardware accelerated
+            if (info.getName().startsWith("OMX.google.")) {
+                assertFalse(info.isVendor());
+                assertFalse(info.isHardwareAccelerated());
+            }
+
+            // Codec 2.0 based AOSP codecs must run in a software-only process
+            if (info.getName().startsWith("c2.android.")) {
+                assertTrue(info.isSoftwareOnly());
+                assertFalse(info.isVendor());
+                assertFalse(info.isHardwareAccelerated());
+            }
+
+            // validate aliases
+            if (info.isAlias()) {
+                assertFalse(info.getName().equals(info.getCanonicalName()));
+                testCanonicalCodecIsNotAnAlias(info.getCanonicalName());
+            } else {
+                // validate codec names: (Canonical) codec names must be meaningful.
+                // We only test this on canonical infos as we allow aliases to support
+                // existing codec names that do not fit this.
+                assertEquals(info.getName(), info.getCanonicalName());
+                testKindInCodecNamesIsMeaningful(info);
+                testMediaTypeInCodecNamesIsMeaningful(info);
+            }
+
+            // hardware accelerated codecs cannot be software only
+            assertFalse(info.isHardwareAccelerated() && info.isSoftwareOnly());
+        }
+    }
+
+    public void testVideoPerformancePointsSanity() {
+        MediaFormat hd25Format =
+            MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720);
+        hd25Format.setFloat(MediaFormat.KEY_FRAME_RATE, 25.f);
+
+        MediaFormat portraitHd240Format =
+            MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 720, 1280);
+        portraitHd240Format.setInteger(MediaFormat.KEY_FRAME_RATE, 240);
+
+        assertTrue(VideoCapabilities.PerformancePoint.HD_30.covers(hd25Format));
+        assertTrue(VideoCapabilities.PerformancePoint.HD_25.covers(hd25Format));
+        assertFalse(VideoCapabilities.PerformancePoint.HD_24.covers(hd25Format));
+        assertTrue(VideoCapabilities.PerformancePoint.FHD_30.covers(hd25Format));
+        assertTrue(VideoCapabilities.PerformancePoint.FHD_25.covers(hd25Format));
+        assertFalse(VideoCapabilities.PerformancePoint.FHD_24.covers(hd25Format));
+
+        assertTrue(VideoCapabilities.PerformancePoint.HD_240.covers(portraitHd240Format));
+        assertFalse(VideoCapabilities.PerformancePoint.HD_200.covers(portraitHd240Format));
+        assertTrue(VideoCapabilities.PerformancePoint.FHD_240.covers(portraitHd240Format));
+        assertFalse(VideoCapabilities.PerformancePoint.FHD_200.covers(portraitHd240Format));
+    }
+
+    public void verifyPerformancePoints(
+            MediaCodecInfo info, String mediaType,
+            List<VideoCapabilities.PerformancePoint> points) {
+        // TODO: verify performance points listed conform to the requirements ... once those
+        // requirements are agreed upon.
+    }
+
+    public void testAllHardwareAcceleratedVideoCodecsPublishPerformancePoints() {
+        List<String> mandatoryTypes = Arrays.asList(
+                MediaFormat.MIMETYPE_VIDEO_AVC,
+                MediaFormat.MIMETYPE_VIDEO_VP8,
+                MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION,
+                MediaFormat.MIMETYPE_VIDEO_HEVC,
+                MediaFormat.MIMETYPE_VIDEO_VP9,
+                MediaFormat.MIMETYPE_VIDEO_AV1);
+
+        String[] featuresToConfig = new String[] {
+            FEATURE_SecurePlayback,
+            FEATURE_TunneledPlayback,
+        };
+
+        for (MediaCodecInfo info : mAllInfos) {
+            String[] types = info.getSupportedTypes();
+            for (int j = 0; j < types.length; ++j) {
+                CodecCapabilities cap = info.getCapabilitiesForType(types[j]);
+                MediaFormat defaultFormat = cap.getDefaultFormat();
+                VideoCapabilities videoCap = cap.getVideoCapabilities();
+
+                Log.d(TAG, "codec: " + info.getName() + " canonical: " + info.getCanonicalName()
+                        + " type: " + types[j]);
+
+                if (videoCap == null) {
+                    assertFalse("no video capabilities for video media type " + types[j] + " of "
+                                    + info.getName(),
+                                types[j].toLowerCase().startsWith("video/"));
+                    continue;
+                }
+
+                List<VideoCapabilities.PerformancePoint> pps =
+                    videoCap.getSupportedPerformancePoints();
+
+                // see which feature combinations are supported by this codec
+                // we do this by counting in binary up to a number of bits
+                List<Integer> supportedFeatureConfigs = new ArrayList<Integer>();
+                for (int cfg_ix = 1 << featuresToConfig.length; --cfg_ix >= 0; ) {
+                    boolean supported = true;
+                    for (int f_ix = 0; supported && f_ix < featuresToConfig.length; ++f_ix) {
+                        if (((cfg_ix >> f_ix) & 1) != 0) {
+                            // feature is to be enabled
+                            supported = supported && cap.isFeatureSupported(featuresToConfig[f_ix]);
+                        } else {
+                            // feature is not to be enabled
+                            supported = supported && !cap.isFeatureRequired(featuresToConfig[f_ix]);
+                        }
+                    }
+                    if (supported) {
+                        supportedFeatureConfigs.add(cfg_ix);
+                    }
+                }
+                int[] supportedFeatureConfigsArray =
+                    supportedFeatureConfigs.stream().mapToInt(Integer::intValue).toArray();
+
+                Log.d(TAG, "codec supports configs "
+                        + Arrays.toString(supportedFeatureConfigsArray));
+                if (pps == null) {
+                    // Hardware-accelerated video components must publish performance points,
+                    // even if it is an empty list.
+                    assertFalse("HW-accelerated codec '" + info.getName()
+                            + "' must publish performance points", info.isHardwareAccelerated());
+
+                    continue;
+                }
+
+                // At least one hardware accelerated codec for each media type (including secure
+                // codecs) must publish valid performance points for AVC/VP8/VP9/HEVC/AV1.
+                if (pps.size() == 0) {
+                    if (mandatoryTypes.contains(types[j])) {
+                        Log.d(TAG, "empty performance points list published by HW accelerated" +
+                                   "component " + info.getName() + " for " + types[j]);
+                    }
+                } else {
+                    for (VideoCapabilities.PerformancePoint p : pps) {
+                        Log.d(TAG, "got performance point "
+                                + p.macroBlocks + "block @ " + p.macroBlockRate / p.macroBlocks
+                                + "fps (max " + p.frameRate + "fps)");
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaFormatTest.java b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
new file mode 100644
index 0000000..2beae2b
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
@@ -0,0 +1,638 @@
+/*
+ * 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 android.media.cts;
+
+import android.media.MediaFormat;
+import android.test.AndroidTestCase;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class MediaFormatTest extends AndroidTestCase {
+    private static ByteBuffer defaultByteBuffer = ByteBuffer.allocateDirect(16);
+
+    private void assertGetByteBuffersThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            ByteBuffer value = format.getByteBuffer(key);
+            throw new AssertionError("read " + type + " as ByteBuffer " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            ByteBuffer value = format.getByteBuffer(key, defaultByteBuffer);
+            throw new AssertionError("read " + type + " with default as ByteBuffer " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetFloatsThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            float value = format.getFloat(key);
+            throw new AssertionError("read " + type + " as float " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            float value = format.getFloat(key, 321.f);
+            throw new AssertionError("read " + type + " with default as float " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetIntegersThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            int value = format.getInteger(key);
+            throw new AssertionError("read " + type + " as int " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            int value = format.getInteger(key, 123);
+            throw new AssertionError("read " + type + " with default as int " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetLongsThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            long value = format.getLong(key);
+            throw new AssertionError("read " + type + " as long " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            long value = format.getLong(key, 321L);
+            throw new AssertionError("read " + type + " with default as long " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetNumbersThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            Number value = format.getNumber(key);
+            throw new AssertionError("read " + type + " as Number " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            Number value = format.getNumber(key, 321.f);
+            throw new AssertionError("read " + type + " with default as Number " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetStringsThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            String value = format.getString(key);
+            throw new AssertionError("read " + type + " as string " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            String value = format.getString(key, "321");
+            throw new AssertionError("read " + type + " with default as string " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    public void testIntegerValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setInteger("int", 123);
+
+        assertEquals(123, format.getInteger("int"));
+
+        // We should be able to read int values as numbers.
+        assertEquals(123, format.getNumber("int").intValue());
+        assertEquals(123, format.getNumber("int", 321).intValue());
+
+        // We should not be able to get an integer value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "int", "int");
+        assertGetFloatsThrowClassCastException(format, "int", "int");
+        assertGetLongsThrowClassCastException(format, "int", "int");
+        assertGetStringsThrowClassCastException(format, "int", "int");
+
+        // We should not have a feature enabled for an integer value
+        try {
+            boolean value = format.getFeatureEnabled("int");
+            throw new AssertionError("read int as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "int", MediaFormat.TYPE_INTEGER);
+    }
+
+    public void testLongValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setLong("long", 9876543210L);
+
+        assertEquals(9876543210L, format.getLong("long"));
+
+        // We should be able to read long values as numbers.
+        assertEquals(9876543210L, format.getNumber("long").longValue());
+        assertEquals(9876543210L, format.getNumber("long", 9012345678L).longValue());
+
+        // We should not be able to get a long value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "long", "long");
+        assertGetFloatsThrowClassCastException(format, "long", "long");
+        assertGetIntegersThrowClassCastException(format, "long", "long");
+        assertGetStringsThrowClassCastException(format, "long", "long");
+
+        // We should not have a feature enabled for a long value
+        try {
+            boolean value = format.getFeatureEnabled("long");
+            throw new AssertionError("read long as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "long", MediaFormat.TYPE_LONG);
+    }
+
+    public void testFloatValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setFloat("float", 3.14f);
+
+        assertEquals(3.14f, format.getFloat("float"));
+
+        // We should be able to read float values as numbers.
+        assertEquals(3.14f, format.getNumber("float").floatValue());
+        assertEquals(3.14f, format.getNumber("float", 2.81f).floatValue());
+
+        // We should not be able to get a float value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "float", "float");
+        assertGetIntegersThrowClassCastException(format, "float", "float");
+        assertGetLongsThrowClassCastException(format, "float", "float");
+        assertGetStringsThrowClassCastException(format, "float", "float");
+
+        // We should not have a feature enabled for a float value
+        try {
+            boolean value = format.getFeatureEnabled("float");
+            throw new AssertionError("read float as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "float", MediaFormat.TYPE_FLOAT);
+    }
+
+    public void testStringValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setString("string", "value");
+
+        assertEquals("value", format.getString("string"));
+
+        // We should not be able to get a string value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "string", "string");
+        assertGetFloatsThrowClassCastException(format, "string", "string");
+        assertGetIntegersThrowClassCastException(format, "string", "string");
+        assertGetLongsThrowClassCastException(format, "string", "string");
+        assertGetNumbersThrowClassCastException(format, "string", "string");
+
+        // We should not have a feature enabled for an integer value
+        try {
+            boolean value = format.getFeatureEnabled("string");
+            throw new AssertionError("read string as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "string", MediaFormat.TYPE_STRING);
+    }
+
+    public void testByteBufferValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        ByteBuffer buffer = ByteBuffer.allocateDirect(123);
+        format.setByteBuffer("buffer", buffer);
+
+        assertEquals(buffer, format.getByteBuffer("buffer"));
+
+        // We should not be able to get a string value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetFloatsThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetIntegersThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetLongsThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetNumbersThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetStringsThrowClassCastException(format, "buffer", "ByteBuffer");
+
+        // We should not have a feature enabled for an integer value
+        try {
+            boolean value = format.getFeatureEnabled("buffer");
+            throw new AssertionError("read ByteBuffer as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "buffer", MediaFormat.TYPE_BYTE_BUFFER);
+    }
+
+    public void testNullStringValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setString("null", null);
+        testNullOrMissingValue(format, "null");
+        testSingleKeyRemoval(format, "null", MediaFormat.TYPE_NULL);
+    }
+
+    public void testNullByteBufferValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setByteBuffer("null", null);
+        testNullOrMissingValue(format, "null");
+        testSingleKeyRemoval(format, "null", MediaFormat.TYPE_NULL);
+    }
+
+    public void testMissingValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        // null values should be handled the same as missing values
+        assertEquals(MediaFormat.TYPE_NULL, format.getValueTypeForKey("missing"));
+        testNullOrMissingValue(format, "missing");
+    }
+
+    private void testSingleKeyRemoval(
+            MediaFormat format, String key, @MediaFormat.Type int type) {
+        assertEquals(type, format.getValueTypeForKey(key));
+        assertTrue(format.containsKey(key));
+
+        Set<String> keySet = format.getKeys();
+        assertEquals(1, keySet.size());
+        assertTrue(keySet.contains(key));
+
+        format.removeKey(key);
+        assertFalse(format.containsKey(key));
+
+        // test that keySet is connected to the format
+        assertFalse(keySet.contains(key));
+        assertEquals(0, keySet.size());
+    }
+
+    private static Set<String> asSet(String ... values) {
+        return new HashSet<>(Arrays.asList(values));
+    }
+
+    private void assertStringSetEquals(Set<String> set, String ... expected_members) {
+        Set<String> expected = new HashSet<>(Arrays.asList(expected_members));
+        assertEquals(expected, set);
+    }
+
+    public void testKeySetContainsAndRemove() {
+        MediaFormat format = new MediaFormat();
+        format.setInteger("int", 123);
+        format.setLong("long", 9876543210L);
+        format.setFloat("float", 321.f);
+        format.setFeatureEnabled("int", true);
+        format.setFeatureEnabled("long", false);
+        format.setFeatureEnabled("float", true);
+        format.setFeatureEnabled("string", false);
+
+        Set<String> keySet = format.getKeys();
+        // test size and contains
+        assertEquals(3, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertTrue(keySet.contains("long"));
+        assertTrue(keySet.contains("float"));
+        assertFalse(keySet.contains("string"));
+        assertStringSetEquals(keySet, "int", "long", "float");
+
+        // test adding an element
+        format.setString("string", "value");
+
+        // test that key set reflects format change in size and contains
+        assertEquals(4, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertTrue(keySet.contains("long"));
+        assertTrue(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+
+        // test iterator
+        {
+            Set<String> toFind = asSet("int", "long", "float", "string");
+            Iterator<String> it = keySet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // remove via format
+        format.removeKey("float");
+
+        // test that key set reflects format change in size and contains
+        assertEquals(3, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertTrue(keySet.contains("long"));
+        assertFalse(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+
+        // re-test iterator after removal
+        {
+            Set<String> toFind = asSet("int", "long", "string");
+            for (String k : keySet) {
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test remove
+        keySet.remove("long");
+        assertEquals(2, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertFalse(keySet.contains("long"));
+        assertFalse(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+        assertTrue(format.containsKey("int"));
+        assertFalse(format.containsKey("long"));
+        assertFalse(format.containsKey("float"));
+        assertTrue(format.containsKey("string"));
+
+        // test iterator by its interface as well as its remove
+        {
+            Set<String> toFind = asSet("int", "string");
+            Iterator<String> it = keySet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+                if (k.equals("int")) {
+                    it.remove();
+                }
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test that removing via iterator also removes from format
+        assertEquals(1, keySet.size());
+        assertFalse(keySet.contains("int"));
+        assertFalse(keySet.contains("long"));
+        assertFalse(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+        assertFalse(format.containsKey("int"));
+        assertFalse(format.containsKey("long"));
+        assertFalse(format.containsKey("float"));
+        assertTrue(format.containsKey("string"));
+
+        // verify that features are still present
+        assertTrue(format.getFeatureEnabled("int"));
+        assertFalse(format.getFeatureEnabled("long"));
+        assertTrue(format.getFeatureEnabled("float"));
+        assertFalse(format.getFeatureEnabled("string"));
+    }
+
+    public void testFeatureKeySetContainsAndRemove() {
+        MediaFormat format = new MediaFormat();
+        format.setInteger("int", 123);
+        format.setLong("long", 9876543210L);
+        format.setFloat("float", 321.f);
+        format.setString("string", "value");
+        format.setFeatureEnabled("int", true);
+        format.setFeatureEnabled("long", false);
+        format.setFeatureEnabled("float", true);
+
+        Set<String> featureSet = format.getFeatures();
+        // test size and contains
+        assertEquals(3, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertTrue(featureSet.contains("long"));
+        assertTrue(featureSet.contains("float"));
+        assertFalse(featureSet.contains("string"));
+        assertStringSetEquals(featureSet, "int", "long", "float");
+
+        // test adding an element
+        format.setFeatureEnabled("string", false);
+
+        // test that key set reflects format change in size and contains
+        assertEquals(4, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertTrue(featureSet.contains("long"));
+        assertTrue(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        // test iterator
+        {
+            Set<String> toFind = asSet("int", "long", "float", "string");
+            Iterator<String> it = featureSet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test that features cannot be removed via format as keys, even though for backward
+        // compatibility, they can be accessed as integers and can be found via containsKey
+        format.removeKey("feature-float");
+        assertEquals(4, featureSet.size());
+        assertTrue(featureSet.contains("float"));
+
+        format.removeFeature("float");
+
+        // TODO: deprecate this usage
+        assertEquals(1, format.getInteger("feature-int"));
+        assertEquals(0, format.getInteger("feature-long"));
+        assertTrue(format.containsKey("feature-int"));
+
+        // Along these lines also verify that this is not true for the getKeys() set
+        assertFalse(format.getKeys().contains("feature-int"));
+
+        // Also verify that getKeys() cannot be used to remove a feature
+        assertFalse(format.getKeys().remove("feature-int"));
+
+        // test that key set reflects format change in size and contains
+        assertEquals(3, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertTrue(featureSet.contains("long"));
+        assertFalse(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        // re-test iterator after removal
+        {
+            Set<String> toFind = asSet("int", "long", "string");
+            for (String k : featureSet) {
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test remove via set
+        featureSet.remove("long");
+        assertEquals(2, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertFalse(featureSet.contains("long"));
+        assertFalse(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        assertTrue(format.containsFeature("int"));
+        assertFalse(format.containsFeature("long"));
+        assertFalse(format.containsFeature("float"));
+        assertTrue(format.containsFeature("string"));
+
+        assertTrue(format.getFeatureEnabled("int"));
+        try {
+            format.getFeatureEnabled("long");
+            fail("should not contain feature long");
+        } catch (IllegalArgumentException e) {}
+        try {
+            format.getFeatureEnabled("float");
+            fail("should not contain feature float");
+        } catch (IllegalArgumentException e) {}
+        assertFalse(format.getFeatureEnabled("string"));
+
+        // test iterator by its interface as well as its remove
+        {
+            Set<String> toFind = asSet("int", "string");
+            Iterator<String> it = featureSet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+                if (k.equals("int")) {
+                    it.remove();
+                }
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test that removing via iterator also removes from format
+        assertEquals(1, featureSet.size());
+        assertFalse(featureSet.contains("int"));
+        assertFalse(featureSet.contains("long"));
+        assertFalse(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        assertFalse(format.containsFeature("int"));
+        assertFalse(format.containsFeature("long"));
+        assertFalse(format.containsFeature("float"));
+        assertTrue(format.containsFeature("string"));
+
+        try {
+            format.getFeatureEnabled("int");
+            fail("should not contain feature int");
+        } catch (IllegalArgumentException e) {}
+        try {
+            format.getFeatureEnabled("long");
+            fail("should not contain feature long");
+        } catch (IllegalArgumentException e) {}
+        try {
+            format.getFeatureEnabled("float");
+            fail("should not contain feature float");
+        } catch (IllegalArgumentException e) {}
+        assertFalse(format.getFeatureEnabled("string"));
+
+        // verify that keys are still present
+        assertEquals(123, format.getInteger("int"));
+        assertEquals(9876543210L, format.getLong("long"));
+        assertEquals(321.f, format.getFloat("float"));
+        assertEquals("value", format.getString("string"));
+    }
+
+    private void testNullOrMissingValue(MediaFormat format, String key) throws Exception {
+        // We should not be able to get a string value as any primitive type. Instead,
+        // we should receive a NullPointerException
+        try {
+            int value = format.getInteger(key);
+            throw new AssertionError("read " + key + " as int " + value);
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            long value = format.getLong(key);
+            throw new AssertionError("read " + key + " as long " + value);
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            float value = format.getFloat(key);
+            throw new AssertionError("read " + key + " as float " + value);
+        } catch (NullPointerException e) {
+        }
+
+        // We should get null for all object types (ByteBuffer, Number, String)
+        assertNull(format.getNumber(key));
+        assertNull(format.getString(key));
+        assertNull(format.getByteBuffer(key));
+
+        // We should get the default value for all getters with default
+        assertEquals(123, format.getInteger(key, 123));
+        assertEquals(321L, format.getLong(key, 321L));
+        assertEquals(321.f, format.getFloat(key, 321.f));
+        assertEquals(321.f, format.getNumber(key, 321.f));
+        assertEquals("value", format.getString(key, "value"));
+        assertEquals(defaultByteBuffer, format.getByteBuffer(key, defaultByteBuffer));
+
+        // We should not have a feature enabled for a null value
+        try {
+            boolean value = format.getFeatureEnabled(key);
+            throw new AssertionError("read " + key + " as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    public void testMediaFormatConstructors() {
+        MediaFormat format;
+        {
+            format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 6);
+            assertEquals(MediaFormat.MIMETYPE_AUDIO_AAC, format.getString(MediaFormat.KEY_MIME));
+            assertEquals(48000, format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
+            assertEquals(6, format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
+            assertEquals(3, format.getKeys().size());
+            assertEquals(0, format.getFeatures().size());
+        }
+
+        {
+            format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1920, 1080);
+            assertEquals(MediaFormat.MIMETYPE_VIDEO_AVC, format.getString(MediaFormat.KEY_MIME));
+            assertEquals(1920, format.getInteger(MediaFormat.KEY_WIDTH));
+            assertEquals(1080, format.getInteger(MediaFormat.KEY_HEIGHT));
+            assertEquals(3, format.getKeys().size());
+            assertEquals(0, format.getFeatures().size());
+        }
+
+        {
+            format = MediaFormat.createSubtitleFormat(MediaFormat.MIMETYPE_TEXT_VTT, "und");
+            assertEquals(MediaFormat.MIMETYPE_TEXT_VTT, format.getString(MediaFormat.KEY_MIME));
+            assertEquals("und", format.getString(MediaFormat.KEY_LANGUAGE));
+            assertEquals(2, format.getKeys().size());
+            assertEquals(0, format.getFeatures().size());
+
+            format.setFeatureEnabled("feature1", false);
+
+            // also test dup
+            MediaFormat other = new MediaFormat(format);
+            format.setString(MediaFormat.KEY_LANGUAGE, "un");
+            other.setInteger(MediaFormat.KEY_IS_DEFAULT, 1);
+            other.setFeatureEnabled("feature1", true);
+
+            assertEquals(MediaFormat.MIMETYPE_TEXT_VTT, format.getString(MediaFormat.KEY_MIME));
+            assertEquals("un", format.getString(MediaFormat.KEY_LANGUAGE));
+            assertEquals(2, format.getKeys().size());
+            assertFalse(format.getFeatureEnabled("feature1"));
+            assertEquals(1, format.getFeatures().size());
+
+            assertEquals(MediaFormat.MIMETYPE_TEXT_VTT, other.getString(MediaFormat.KEY_MIME));
+            assertEquals("und", other.getString(MediaFormat.KEY_LANGUAGE));
+            assertEquals(1, other.getInteger(MediaFormat.KEY_IS_DEFAULT));
+            assertEquals(3, other.getKeys().size());
+            assertTrue(other.getFeatureEnabled("feature1"));
+            assertEquals(1, other.getFeatures().size());
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
index 0d1796a..c19dba5 100644
--- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
@@ -464,9 +464,8 @@
                 verifyAttributesMatch(srcMedia, outputMediaFile, degrees);
                 verifyLocationInFile(outputMediaFile);
             }
-            // Check the sample on 1s and 0.5s.
-            verifySamplesMatch(srcMedia, outputMediaFile, 1000000);
-            verifySamplesMatch(srcMedia, outputMediaFile, 500000);
+            // Verify timestamp of all samples.
+            verifyTimestampsWithSamplesDropSet(srcMedia, outputMediaFile, null, null);
         } finally {
             new File(outputMediaFile).delete();
         }
@@ -1003,15 +1002,12 @@
                 }
                 extractorSrc.selectTrack(videoTrackIndex);
                 extractorTest.selectTrack(videoTrackIndex);
+                checkVideoSamplesTimeStamps(extractorSrc, extractorTest, samplesDropSet,
+                    videoStartOffsetUs);
+                extractorSrc.unselectTrack(videoTrackIndex);
+                extractorTest.unselectTrack(videoTrackIndex);
             }
         }
-        if (videoTrackIndex != -1) {
-            checkVideoSamplesTimeStamps(extractorSrc, extractorTest, samplesDropSet,
-                videoStartOffsetUs);
-        }
-
-        extractorSrc.unselectTrack(videoTrackIndex);
-        extractorTest.unselectTrack(videoTrackIndex);
 
         int audioTrackIndex = -1;
         int audioSampleCount = 0;
@@ -1026,14 +1022,10 @@
                 }
                 extractorSrc.selectTrack(audioTrackIndex);
                 extractorTest.selectTrack(audioTrackIndex);
+                checkAudioSamplesTimestamps(extractorSrc, extractorTest, audioStartOffsetUs);
             }
         }
 
-        if (audioTrackIndex != -1) {
-           // No audio track
-            checkAudioSamplesTimestamps(extractorSrc, extractorTest, audioStartOffsetUs);
-        }
-
         extractorSrc.release();
         extractorTest.release();
         srcFd.close();
@@ -1057,10 +1049,10 @@
             srcSampleTimeUs = extractorSrc.getSampleTime();
             testSampleTimeUs = extractorTest.getSampleTime();
             if (VERBOSE) {
-                Log.d(TAG, "videoSampleCount:" + videoSampleCount);
-                Log.d(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
+                Log.i(TAG, "videoSampleCount:" + videoSampleCount);
+                Log.i(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
                             "  testTrackIndex:" + extractorTest.getSampleTrackIndex());
-                Log.d(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
+                Log.i(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
             }
             if (samplesDropSet == null || !samplesDropSet.contains(videoSampleCount)) {
                 if (srcSampleTimeUs == -1 || testSampleTimeUs == -1) {
@@ -1114,6 +1106,7 @@
             srcSampleTimeUs = extractorSrc.getSampleTime();
             testSampleTimeUs = extractorTest.getSampleTime();
             if(VERBOSE) {
+                Log.d(TAG, "audioSampleCount:" + audioSampleCount);
                 Log.v(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
                             "  testTrackIndex:" + extractorTest.getSampleTrackIndex());
                 Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
@@ -1137,22 +1130,12 @@
             else if ((audioSampleCount > 1 &&
                 (srcSampleTimeUs + audioStartOffsetUs) != testSampleTimeUs) ||
                 (audioSampleCount == 1 && srcSampleTimeUs != testSampleTimeUs)) {
-                    if (VERBOSE) {
-                        Log.d(TAG, "Fail:audio timestamps didn't match");
-                        Log.d(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
-                            "  testTrackIndex:" + extractorTest.getSampleTrackIndex());
-                        Log.d(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
-                        Log.d(TAG, "audioSampleCount:" + audioSampleCount);
-                    }
                     fail("audio timestamps didn't match");
                 }
             testAdvance = extractorTest.advance();
             srcAdvance = extractorSrc.advance();
         } while(srcAdvance && testAdvance);
         if (srcAdvance != testAdvance) {
-            if (VERBOSE) {
-                Log.d(TAG, "audioSampleCount:" + audioSampleCount);
-            }
             fail("either audio track has not reached its last sample");
         }
     }
diff --git a/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java b/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java
new file mode 100644
index 0000000..aa9894f
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java
@@ -0,0 +1,462 @@
+/*
+ * 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.media.cts;
+
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.opengl.GLES20;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.RequiresDevice;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+@SmallTest
+@RequiresDevice
+public class SurfaceEncodeTimestampTest extends AndroidTestCase {
+    private static final String TAG = SurfaceEncodeTimestampTest.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private static final Color COLOR_BLOCK =
+            Color.valueOf(1.0f, 1.0f, 1.0f);
+    private static final Color[] COLOR_BARS = {
+            Color.valueOf(0.0f, 0.0f, 0.0f),
+            Color.valueOf(0.0f, 0.0f, 0.64f),
+            Color.valueOf(0.0f, 0.64f, 0.0f),
+            Color.valueOf(0.0f, 0.64f, 0.64f),
+            Color.valueOf(0.64f, 0.0f, 0.0f),
+            Color.valueOf(0.64f, 0.0f, 0.64f),
+            Color.valueOf(0.64f, 0.64f, 0.0f),
+    };
+    private static final int BORDER_WIDTH = 16;
+
+    private Handler mHandler;
+    private HandlerThread mHandlerThread;
+    private MediaCodec mEncoder;
+    private InputSurface mInputEglSurface;
+    private int mInputCount;
+
+    @Override
+    public void setUp() throws Exception {
+        if (mHandlerThread == null) {
+            mHandlerThread = new HandlerThread(
+                    "EncoderThread", Process.THREAD_PRIORITY_FOREGROUND);
+            mHandlerThread.start();
+            mHandler = new Handler(mHandlerThread.getLooper());
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mHandler = null;
+        if (mHandlerThread != null) {
+            mHandlerThread.quit();
+            mHandlerThread = null;
+        }
+    }
+
+    /*
+     * Test KEY_MAX_PTS_GAP_TO_ENCODER
+     *
+     * This key is supposed to cap the gap between any two frames fed to the encoder,
+     * and restore the output pts back to the original. Since the pts is not supposed
+     * to be modified, we can't really verify that the "capping" actually took place.
+     * However, we can at least verify that the pts is preserved.
+     */
+    public void testMaxPtsGap() throws Throwable {
+        long[] inputPts = {1000000, 2000000, 3000000, 4000000};
+        long[] expectedOutputPts = {1000000, 2000000, 3000000, 4000000};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, 33333);
+        });
+    }
+
+    /*
+     * Test that by default backward-going frames get dropped.
+     */
+    public void testBackwardFrameDroppedWithoutFixedPtsGap() throws Throwable {
+        long[] inputPts = {33333, 66667, 66000, 100000};
+        long[] expectedOutputPts = {33333, 66667, 100000};
+        doTest(inputPts, expectedOutputPts, null);
+    }
+
+    /*
+     * Test KEY_MAX_PTS_GAP_TO_ENCODER
+     *
+     * Test that when fixed pts gap is used, backward-going frames are accepted
+     * and the pts is preserved.
+     */
+    public void testBackwardFramePreservedWithFixedPtsGap() throws Throwable {
+        long[] inputPts = {33333, 66667, 66000, 100000};
+        long[] expectedOutputPts = {33333, 66667, 66000, 100000};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, -33333);
+        });
+    }
+
+    /*
+     * Test KEY_MAX_FPS_TO_ENCODER
+     *
+     * Input frames are timestamped at 60fps, the key is supposed to drop
+     * one every other frame to maintain 30fps output.
+     */
+    public void testMaxFps() throws Throwable {
+        long[] inputPts = {16667, 33333, 50000, 66667, 83333};
+        long[] expectedOutputPts = {16667, 50000, 83333};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setFloat(MediaFormat.KEY_MAX_FPS_TO_ENCODER, 30.0f);
+        });
+    }
+
+    /*
+     * Test KEY_REPEAT_PREVIOUS_FRAME_AFTER
+     *
+     * Test that the frame is repeated at least once if no new frame arrives after
+     * the specified amount of time.
+     */
+    public void testRepeatPreviousFrameAfter() throws Throwable {
+        long[] inputPts = {16667, 33333, -100000, 133333};
+        long[] expectedOutputPts = {16667, 33333, 103333};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 70000);
+        });
+    }
+
+    /*
+     * Test KEY_CREATE_INPUT_SURFACE_SUSPENDED and PARAMETER_KEY_SUSPEND
+     *
+     * Start the encoder with KEY_CREATE_INPUT_SURFACE_SUSPENDED set, then resume
+     * by PARAMETER_KEY_SUSPEND. Verify only frames after resume are captured.
+     */
+    public void testCreateInputSurfaceSuspendedResume() throws Throwable {
+        // Using PARAMETER_KEY_SUSPEND (instead of PARAMETER_KEY_SUSPEND +
+        // PARAMETER_KEY_SUSPEND_TIME) to resume doesn't enforce a time
+        // for the action to take effect. Due to the asynchronous operation
+        // between the MediaCodec's parameters and the input surface, frames
+        // rendered before the resume call may reach encoder input side after
+        // the resume. Here we do a slight wait (100000us) to make sure that
+        // the resume only takes effect on the frame with timestamp 100000.
+        long[] inputPts = {33333, 66667, -100000, 100000, 133333};
+        long[] expectedOutputPts = {100000, 133333};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setInteger(MediaFormat.KEY_CREATE_INPUT_SURFACE_SUSPENDED, 1);
+        }, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+            return params;
+        });
+    }
+
+    /*
+     * Test KEY_CREATE_INPUT_SURFACE_SUSPENDED,
+     * PARAMETER_KEY_SUSPEND and PARAMETER_KEY_SUSPEND_TIME
+     *
+     * Start the encoder with KEY_CREATE_INPUT_SURFACE_SUSPENDED set, then request resume
+     * at specific time using PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME.
+     * Verify only frames after the specified time are captured.
+     */
+     public void testCreateInputSurfaceSuspendedResumeWithTime() throws Throwable {
+         // Unlike using PARAMETER_KEY_SUSPEND alone to resume, using PARAMETER_KEY_SUSPEND
+         // + PARAMETER_KEY_SUSPEND_TIME to resume can be scheduled any time before the
+         // frame with the specified time arrives. Here we do it immediately after start.
+         long[] inputPts = {-1, 33333, 66667, 100000, 133333};
+         long[] expectedOutputPts = {100000, 133333};
+         doTest(inputPts, expectedOutputPts, (format) -> {
+             format.setInteger(MediaFormat.KEY_CREATE_INPUT_SURFACE_SUSPENDED, 1);
+         }, () -> {
+             Bundle params = new Bundle();
+             params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+             params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 100000);
+             return params;
+         });
+    }
+
+     /*
+      * Test PARAMETER_KEY_SUSPEND.
+      *
+      * Suspend/resume during capture, and verify that frames during the suspension
+      * period are dropped.
+      */
+    public void testSuspendedResume() throws Throwable {
+        // Using PARAMETER_KEY_SUSPEND (instead of PARAMETER_KEY_SUSPEND +
+        // PARAMETER_KEY_SUSPEND_TIME) to suspend/resume doesn't enforce a time
+        // for the action to take effect. Due to the asynchronous operation
+        // between the MediaCodec's parameters and the input surface, frames
+        // rendered before the request may reach encoder input side after
+        // the request. Here we do a slight wait (100000us) to make sure that
+        // the suspend/resume only takes effect on the next frame.
+        long[] inputPts = {33333, 66667, -100000, 100000, 133333, -100000, 166667};
+        long[] expectedOutputPts = {33333, 66667, 166667};
+        doTest(inputPts, expectedOutputPts, null, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 1);
+            return params;
+        }, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+            return params;
+        });
+    }
+
+    /*
+     * Test PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME.
+     *
+     * Suspend/resume with specified time during capture, and verify that frames during
+     * the suspension period are dropped.
+     */
+    public void testSuspendedResumeWithTime() throws Throwable {
+        // Unlike using PARAMETER_KEY_SUSPEND alone to suspend/resume, requests using
+        // PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME can be scheduled any time
+        // before the frame with the specified time arrives. Queue both requests shortly
+        // after start and test that they take place at the proper frames.
+        long[] inputPts = {-1, 33333, -1, 66667, 100000, 133333, 166667};
+        long[] expectedOutputPts = {33333, 66667, 166667};
+        doTest(inputPts, expectedOutputPts, null, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 1);
+            params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 100000);
+            return params;
+        }, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+            params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 166667);
+            return params;
+        });
+    }
+
+    /*
+     * Test PARAMETER_KEY_OFFSET_TIME.
+     *
+     * Apply PARAMETER_KEY_OFFSET_TIME during capture, and verify that the pts
+     * of frames after the request are adjusted by the offset correctly.
+     */
+    public void testOffsetTime() throws Throwable {
+        long[] inputPts = {33333, 66667, -100000, 100000, 133333};
+        long[] expectedOutputPts = {33333, 66667, 83333, 116666};
+        doTest(inputPts, expectedOutputPts, null, () -> {
+            Bundle params = new Bundle();
+            params.putLong(MediaCodec.PARAMETER_KEY_OFFSET_TIME, -16667);
+            return params;
+        });
+    }
+
+    private void doTest(long[] inputPtsUs, long[] expectedOutputPtsUs,
+            Consumer<MediaFormat> configSetter, Supplier<Bundle>... paramGetter) throws Exception {
+
+        try {
+            if (DEBUG) Log.d(TAG, "started");
+
+            // setup surface encoder format
+            mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
+            MediaFormat codecFormat = MediaFormat.createVideoFormat(
+                    MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720);
+            codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
+            codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+                    CodecCapabilities.COLOR_FormatSurface);
+            codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
+            codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+                    MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
+            codecFormat.setInteger(MediaFormat.KEY_BIT_RATE, 6000000);
+
+            if (configSetter != null) {
+                configSetter.accept(codecFormat);
+            }
+
+            CountDownLatch latch = new CountDownLatch(1);
+
+            // configure and start encoder
+            long[] actualOutputPtsUs = new long[expectedOutputPtsUs.length];
+            mEncoder.setCallback(new EncoderCallback(latch, actualOutputPtsUs), mHandler);
+            mEncoder.configure(codecFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+            mInputEglSurface = new InputSurface(mEncoder.createInputSurface());
+
+            mEncoder.start();
+
+            mInputCount = 0;
+            int paramIndex = 0;
+            // perform input operations
+            for (int i = 0; i < inputPtsUs.length; i++) {
+                if (DEBUG) Log.d(TAG, "drawFrame: " + i + ", pts " + inputPtsUs[i]);
+
+                if (inputPtsUs[i] < 0) {
+                    if (inputPtsUs[i] < -1) {
+                        // larger negative number means that a sleep is required
+                        // before the parameter test.
+                        Thread.sleep(-inputPtsUs[i]/1000);
+                    }
+                    if (paramIndex < paramGetter.length && paramGetter[paramIndex] != null) {
+                        // this means a pause to apply parameter to be tested
+                        mEncoder.setParameters(paramGetter[paramIndex].get());
+                    }
+                    paramIndex++;
+                } else {
+                    drawFrame(1280, 720, inputPtsUs[i]);
+                }
+            }
+
+            // if it worked there is really no reason to take longer..
+            latch.await(1000, TimeUnit.MILLISECONDS);
+
+            // verify output timestamps
+            assertTrue("mismatch in output timestamp",
+                    Arrays.equals(expectedOutputPtsUs, actualOutputPtsUs));
+
+            if (DEBUG) Log.d(TAG, "stopped");
+        } finally {
+            if (mEncoder != null) {
+                mEncoder.stop();
+                mEncoder.release();
+                mEncoder = null;
+            }
+            if (mInputEglSurface != null) {
+                // This also releases the surface from encoder.
+                mInputEglSurface.release();
+                mInputEglSurface = null;
+            }
+        }
+    }
+
+    class EncoderCallback extends MediaCodec.Callback {
+        private boolean mOutputEOS;
+        private int mOutputCount;
+        private final CountDownLatch mLatch;
+        private final long[] mActualOutputPts;
+        private final int mMaxOutput;
+
+        EncoderCallback(CountDownLatch latch, long[] actualOutputPts) {
+            mLatch = latch;
+            mActualOutputPts = actualOutputPts;
+            mMaxOutput = actualOutputPts.length;
+        }
+
+        @Override
+        public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+            if (codec != mEncoder) return;
+            if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
+        }
+
+        @Override
+        public void onInputBufferAvailable(MediaCodec codec, int index) {
+            if (codec != mEncoder) return;
+            if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index);
+        }
+
+        @Override
+        public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
+            if (codec != mEncoder || mOutputEOS) return;
+
+            if (DEBUG) {
+                Log.d(TAG, "onOutputBufferAvailable: " + index
+                        + ", time " + info.presentationTimeUs
+                        + ", size " + info.size
+                        + ", flags " + info.flags);
+            }
+
+            if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
+                mActualOutputPts[mOutputCount++] = info.presentationTimeUs;
+            }
+
+            mOutputEOS |= ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) ||
+                    (mOutputCount == mMaxOutput);
+
+            codec.releaseOutputBuffer(index, false);
+
+            if (mOutputEOS) {
+                stopAndNotify(null);
+            }
+        }
+
+        @Override
+        public void onError(MediaCodec codec, CodecException e) {
+            if (codec != mEncoder) return;
+
+            Log.e(TAG, "onError: " + e);
+            stopAndNotify(e);
+        }
+
+        private void stopAndNotify(CodecException e) {
+            mLatch.countDown();
+        }
+    }
+
+    private void drawFrame(int width, int height, long ptsUs) {
+        mInputEglSurface.makeCurrent();
+        generateSurfaceFrame(mInputCount, width, height);
+        mInputEglSurface.setPresentationTime(1000 * ptsUs);
+        mInputEglSurface.swapBuffers();
+        mInputCount++;
+    }
+
+    private static Rect getColorBarRect(int index, int width, int height) {
+        int barWidth = (width - BORDER_WIDTH * 2) / COLOR_BARS.length;
+        return new Rect(BORDER_WIDTH + barWidth * index, BORDER_WIDTH,
+                BORDER_WIDTH + barWidth * (index + 1), height - BORDER_WIDTH);
+    }
+
+    private static Rect getColorBlockRect(int index, int width, int height) {
+        int blockCenterX = (width / 5) * (index % 4 + 1);
+        return new Rect(blockCenterX - width / 10, height / 6,
+                        blockCenterX + width / 10, height / 3);
+    }
+
+    private void generateSurfaceFrame(int frameIndex, int width, int height) {
+        GLES20.glViewport(0, 0, width, height);
+        GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+        GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+
+        for (int i = 0; i < COLOR_BARS.length; i++) {
+            Rect r = getColorBarRect(i, width, height);
+
+            GLES20.glScissor(r.left, r.top, r.width(), r.height());
+            final Color color = COLOR_BARS[i];
+            GLES20.glClearColor(color.red(), color.green(), color.blue(), 1.0f);
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        }
+
+        Rect r = getColorBlockRect(frameIndex, width, height);
+        GLES20.glScissor(r.left, r.top, r.width(), r.height());
+        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        r.inset(BORDER_WIDTH, BORDER_WIDTH);
+        GLES20.glScissor(r.left, r.top, r.width(), r.height());
+        GLES20.glClearColor(COLOR_BLOCK.red(), COLOR_BLOCK.green(), COLOR_BLOCK.blue(), 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+    }
+}
diff --git a/tests/tests/multiuser/AndroidTest.xml b/tests/tests/multiuser/AndroidTest.xml
index 595fcd5..8edf9d6 100644
--- a/tests/tests/multiuser/AndroidTest.xml
+++ b/tests/tests/multiuser/AndroidTest.xml
@@ -18,6 +18,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="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="CtsMultiUserTestCases.apk" />
diff --git a/tests/tests/nativehardware/AndroidTest.xml b/tests/tests/nativehardware/AndroidTest.xml
index 24b0301..3f11774 100644
--- a/tests/tests/nativehardware/AndroidTest.xml
+++ b/tests/tests/nativehardware/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS Native Hardware test cases">
     <option name="test-suite-tag" value="cts" />
     <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" />
     <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/AndroidManifest.xml b/tests/tests/net/AndroidManifest.xml
index 0bfb650..2a57c10 100644
--- a/tests/tests/net/AndroidManifest.xml
+++ b/tests/tests/net/AndroidManifest.xml
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
diff --git a/tests/tests/neuralnetworks/benchmark/Android.mk b/tests/tests/neuralnetworks/benchmark/Android.mk
index 9670236..067db34 100644
--- a/tests/tests/neuralnetworks/benchmark/Android.mk
+++ b/tests/tests/neuralnetworks/benchmark/Android.mk
@@ -29,7 +29,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test androidx.test.rules \
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test \
     compatibility-device-util ctstestrunner junit NeuralNetworksApiBenchmark_Lib
 LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni
 
diff --git a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
index be6d40e..827b5dd 100644
--- a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
+++ b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
@@ -23,10 +23,9 @@
 import android.os.Bundle;
 import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
+import android.support.test.InstrumentationRegistry;
 import android.util.Pair;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.nn.benchmark.core.BenchmarkException;
 import com.android.nn.benchmark.core.BenchmarkResult;
 import com.android.nn.benchmark.core.InferenceInOutSequence;
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
index 86b1ba0..a841486 100644
--- a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
@@ -33,6 +33,7 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
+import android.service.notification.Condition;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.ArraySet;
@@ -240,6 +241,26 @@
         }
     }
 
+    @Test
+    public void testMethodsExistAndDoNotThrow() throws Exception {
+        // behavior is covered in cts verifier
+
+        if (mActivityManager.isLowRamDevice()) {
+            return;
+        }
+
+        // make sure it gets bound
+        pollForConnection(LegacyConditionProviderService.class, true);
+
+        // request unbind
+        LegacyConditionProviderService.getInstance().onConnected();
+        LegacyConditionProviderService.getInstance().onRequestConditions(
+                Condition.FLAG_RELEVANT_NOW);
+        LegacyConditionProviderService.getInstance().onSubscribe(Uri.EMPTY);
+        LegacyConditionProviderService.getInstance().onUnsubscribe(Uri.EMPTY);
+
+    }
+
     private void addRule(ComponentName cn, int filter, boolean enabled) {
         String id = mNm.addAutomaticZenRule(new AutomaticZenRule("name",
                 cn, Uri.EMPTY, filter, enabled));
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
index 71cf3f2..ff20d4d 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
@@ -36,6 +36,7 @@
 import android.os.ParcelFileDescriptor;
 import android.provider.Telephony;
 import android.service.notification.Adjustment;
+import android.service.notification.NotificationAssistantService;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
@@ -250,6 +251,52 @@
         assertTrue(replyFound);
     }
 
+    @Test
+    public void testOnActionInvoked_methodExists() throws Exception {
+        setUpListeners();
+        final Intent intent = new Intent(Intent.ACTION_MAIN, Telephony.Threads.CONTENT_URI);
+
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        intent.setAction(Intent.ACTION_MAIN);
+
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        Notification.Action action = new Notification.Action.Builder(null, "",
+                pendingIntent).build();
+        // This method has to exist and the call cannot fail
+        mNotificationAssistantService.onActionInvoked("", action,
+                NotificationAssistantService.SOURCE_FROM_APP);
+    }
+
+    @Test
+    public void testOnNotificationDirectReplied_methodExists() throws Exception {
+        setUpListeners();
+        // This method has to exist and the call cannot fail
+        mNotificationAssistantService.onNotificationDirectReplied("");
+    }
+
+    @Test
+    public void testOnNotificationExpansionChanged_methodExists() throws Exception {
+        setUpListeners();
+        // This method has to exist and the call cannot fail
+        mNotificationAssistantService.onNotificationExpansionChanged("", true, true);
+    }
+
+    @Test
+    public void testOnNotificationsSeen_methodExists() throws Exception {
+        setUpListeners();
+        // This method has to exist and the call cannot fail
+        mNotificationAssistantService.onNotificationsSeen(new ArrayList<String>());
+    }
+
+    @Test
+    public void testOnSuggestedReplySent_methodExists() throws Exception {
+        setUpListeners();
+        // This method has to exist and the call cannot fail
+        mNotificationAssistantService.onSuggestedReplySent("", "",
+                NotificationAssistantService.SOURCE_FROM_APP);
+    }
+
     private StatusBarNotification getFirstNotificationFromPackage(String PKG)
             throws InterruptedException {
         StatusBarNotification sbn = mNotificationListenerService.mPosted.poll(SLEEP_TIME,
diff --git a/tests/tests/os/jni/Android.bp b/tests/tests/os/jni/Android.bp
new file mode 100644
index 0000000..752146f
--- /dev/null
+++ b/tests/tests/os/jni/Android.bp
@@ -0,0 +1,82 @@
+// Copyright (C) 2010 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_defaults {
+    name: "libctsos_jni_defaults",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-inline-asm",
+        "-Wno-unused-const-variable",
+    ],
+
+    shared_libs: [
+        "libnativehelper_compat_libc++",
+        "liblog",
+        "libdl",
+        "libandroid",
+    ],
+    stl: "libc++_static",
+}
+
+cc_library_shared {
+    name: "libctsos_jni",
+    defaults: ["libctsos_jni_defaults"],
+
+    srcs: [
+        "CtsOsJniOnLoad.cpp",
+        "android_os_cts_TaggedPointer.cpp",
+        "android_os_cts_HardwareName.cpp",
+        "android_os_cts_OSFeatures.cpp",
+        "android_os_cts_NoExecutePermissionTest.cpp",
+        "android_os_cts_SeccompTest.cpp",
+        "android_os_cts_SharedMemory.cpp",
+        "android_os_cts_SPMITest.cpp",
+    ],
+
+    whole_static_libs: ["libctsos_jni_arm"],
+    static_libs: [
+        "libminijail",
+        "external_seccomp_tests",
+    ],
+
+    // This define controls the behavior of OSFeatures.needsSeccompSupport().
+    // TODO(b/124189460): This was reset before use in Android.mk
+    //cflags: ["-DARCH_SUPPORTS_SECCOMP"],
+}
+
+cc_library_static {
+    name: "libctsos_jni_arm",
+    defaults: ["libctsos_jni_defaults"],
+
+    srcs: ["android_os_cts_CpuInstructions.cpp"],
+
+    arch: {
+        arm: {
+            cppflags: [
+                // Let's overwrite -mcpu in case it's set to some ARMv8 core by
+                // TARGET_2ND_CPU_VARIANT and causes clang to ignore the -march below.
+                "-mcpu=generic",
+
+                // The ARM version of this library must be built using ARMv7 ISA (even if it
+                // can be run on armv8 cores) since one of the tested instruction, swp, is
+                // only supported in ARMv7 (and older) cores, and obsolete in ARMv8.
+                "-march=armv7-a",
+            ],
+            instruction_set: "arm",
+        },
+    },
+}
diff --git a/tests/tests/os/jni/Android.mk b/tests/tests/os/jni/Android.mk
deleted file mode 100644
index 58b9d01..0000000
--- a/tests/tests/os/jni/Android.mk
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) 2010 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 := libctsos_jni
-
-# Don't include this package in any configuration by default.
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-		CtsOsJniOnLoad.cpp \
-		android_os_cts_CpuInstructions.cpp.arm \
-		android_os_cts_TaggedPointer.cpp \
-		android_os_cts_HardwareName.cpp \
-		android_os_cts_OSFeatures.cpp \
-		android_os_cts_NoExecutePermissionTest.cpp \
-		android_os_cts_SeccompTest.cpp \
-		android_os_cts_SharedMemory.cpp \
-		android_os_cts_SPMITest.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := libnativehelper_compat_libc++ liblog libdl libandroid
-LOCAL_CXX_STL := none
-
-LOCAL_STATIC_LIBRARIES := libc++_static libminijail
-
-# Select the architectures on which seccomp-bpf are supported. This is used to
-# include extra test files that will not compile on architectures where it is
-# not supported.
-ARCH_SUPPORTS_SECCOMP := 1
-ifeq ($(strip $(TARGET_ARCH)),mips)
-	ARCH_SUPPORTS_SECCOMP = 0
-endif
-ifeq ($(strip $(TARGET_ARCH)),mips64)
-	ARCH_SUPPORTS_SECCOMP = 0
-endif
-
-ifeq ($(ARCH_SUPPORTS_SECCOMP),1)
-	LOCAL_STATIC_LIBRARIES += external_seccomp_tests
-
-	# This define controls the behavior of OSFeatures.needsSeccompSupport().
-	LOCAL_CFLAGS += -DARCH_SUPPORTS_SECCOMP
-endif
-
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
-LOCAL_CFLAGS += -Wno-inline-asm -Wno-unused-const-variable
-
-# Let's overwrite -mcpu in case it's set to some ARMv8 core by
-# TARGET_2ND_CPU_VARIANT and causes clang to ignore the -march below.
-LOCAL_CPPFLAGS_arm := -mcpu=generic
-
-# The ARM version of this library must be built using ARMv7 ISA (even if it
-# can be run on armv8 cores) since one of the tested instruction, swp, is
-# only supported in ARMv7 (and older) cores, and obsolete in ARMv8.
-LOCAL_CPPFLAGS_arm += -march=armv7-a
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java
index a4f956b..0b03458 100644
--- a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java
@@ -151,8 +151,8 @@
     }
 
     @Test
-    public void testToString() {
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+    public void testToString() throws Exception {
+        ParcelFileDescriptor pfd = makeParcelFileDescriptor(getContext());
         assertNotNull(pfd.toString());
     }
 
@@ -206,8 +206,8 @@
     }
 
     @Test
-    public void testGetFileDescriptor() {
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+    public void testGetFileDescriptor() throws Exception {
+        ParcelFileDescriptor pfd = makeParcelFileDescriptor(getContext());
         assertNotNull(pfd.getFileDescriptor());
 
         ParcelFileDescriptor p = new ParcelFileDescriptor(pfd);
@@ -215,8 +215,8 @@
     }
 
     @Test
-    public void testDescribeContents() {
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+    public void testDescribeContents() throws Exception{
+        ParcelFileDescriptor pfd = makeParcelFileDescriptor(getContext());
         assertTrue((Parcelable.CONTENTS_FILE_DESCRIPTOR & pfd.describeContents()) != 0);
     }
 
diff --git a/tests/tests/permission/AndroidManifest.xml b/tests/tests/permission/AndroidManifest.xml
index 928da95..5400c7d 100644
--- a/tests/tests/permission/AndroidManifest.xml
+++ b/tests/tests/permission/AndroidManifest.xml
@@ -32,33 +32,8 @@
                 android:permissionGroup="android.permission.cts.groupC"
                 android:description="@string/perm_c" />
 
-    <!-- for android.permission.cts.PermissionUsage -->
-    <permission android:name="android.permission.cts.D"
-                android:usageInfoRequired="true" />
-
-    <!-- for android.permission.cts.PermissionUsage and LocationAccessCheckTest -->
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
-      android:dataSentOffDevice="no"
-      android:dataSharedWithThirdParty="no"
-      android:dataUsedForMonetization="no"
-      android:dataRetentionTime="notRetained" />
-
-    <!-- for android.permission.cts.PermissionUsage -->
-    <uses-permission android:name="android.permission.READ_PHONE_STATE"
-      android:dataSentOffDevice="yes"
-      android:dataSharedWithThirdParty="yes"
-      android:dataUsedForMonetization="yes"
-      android:dataRetentionTime="32" />
-
-    <!-- for android.permission.cts.PermissionUsage -->
-    <uses-permission android:name="android.permission.RECORD_AUDIO"
-      android:dataSentOffDevice="userTriggered"
-      android:dataSharedWithThirdParty="userTriggered"
-      android:dataUsedForMonetization="userTriggered"
-      android:dataRetentionTime="unlimited" />
-
-    <!-- for android.permission.cts.PermissionUsage -->
-    <uses-permission android:name="android.permission.READ_CALENDAR" />
+    <!-- for android.permission.cts.LocationAccessCheckTest -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 
     <!-- for android.permission.cts.PermissionGroupChange -->
     <permission-group android:description="@string/perm_group_b"
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java b/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java
deleted file mode 100644
index 39c66a6..0000000
--- a/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java
+++ /dev/null
@@ -1,98 +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.
- */
-
-package android.permission.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
-import android.content.pm.UsesPermissionInfo;
-import android.test.InstrumentationTestCase;
-
-import org.junit.Before;
-
-public final class PermissionUsageTest extends InstrumentationTestCase {
-    private PackageManager mPm;
-    private Context mContext;
-
-    @Override
-    @Before
-    public void setUp() throws Exception {
-        mContext = getInstrumentation().getTargetContext();
-        mPm = mContext.getPackageManager();
-        assertNotNull(mPm);
-    }
-
-    private UsesPermissionInfo getUsesPermissionInfo(String permission) throws Exception {
-        PackageInfo info = mPm.getPackageInfo(mContext.getPackageName(),
-                PackageManager.GET_PERMISSIONS);
-        assertNotNull(info);
-        assertNotNull(info.usesPermissions);
-        for (UsesPermissionInfo upi : info.usesPermissions) {
-            if (permission.equals(upi.getPermission())) {
-                return upi;
-            }
-        }
-        return null;
-    }
-
-    public void testBasic() throws Exception {
-        UsesPermissionInfo upi = getUsesPermissionInfo(Manifest.permission.ACCESS_FINE_LOCATION);
-        assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataSentOffDevice());
-        assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataSharedWithThirdParty());
-        assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataUsedForMonetization());
-        assertEquals(UsesPermissionInfo.RETENTION_NOT_RETAINED, upi.getDataRetention());
-    }
-
-    public void testRetentionWeeks() throws Exception {
-        UsesPermissionInfo upi
-                = getUsesPermissionInfo(Manifest.permission.READ_PHONE_STATE);
-        assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataSentOffDevice());
-        assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataSharedWithThirdParty());
-        assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataUsedForMonetization());
-        assertEquals(UsesPermissionInfo.RETENTION_SPECIFIED, upi.getDataRetention());
-        assertEquals(32, upi.getDataRetentionWeeks());
-    }
-
-    public void testUserTriggered() throws Exception {
-        UsesPermissionInfo upi
-                = getUsesPermissionInfo(Manifest.permission.RECORD_AUDIO);
-        assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED, upi.getDataSentOffDevice());
-        assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED,
-                upi.getDataSharedWithThirdParty());
-        assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED,
-                upi.getDataUsedForMonetization());
-        assertEquals(UsesPermissionInfo.RETENTION_UNLIMITED, upi.getDataRetention());
-    }
-
-    public void testUndefined() throws Exception {
-        UsesPermissionInfo upi
-                = getUsesPermissionInfo(Manifest.permission.READ_CALENDAR);
-        assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataSentOffDevice());
-        assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataSharedWithThirdParty());
-        assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataUsedForMonetization());
-        assertEquals(UsesPermissionInfo.RETENTION_UNDEFINED, upi.getDataRetention());
-    }
-
-    public void testUsageInfoRequired() throws Exception {
-        PermissionInfo pi = mPm.getPermissionInfo("android.permission.cts.D", 0);
-        assertTrue(pi.usageInfoRequired);
-    }
-}
diff --git a/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java
index cf49f50..96eef77 100644
--- a/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.UsesPermissionInfo;
 import android.os.Process;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -65,10 +64,9 @@
         String pkg = pkgs[0];
 
         final PackageInfo packageInfo = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
-        assertNotNull("No permissions found for " + pkg, packageInfo.usesPermissions);
+        assertNotNull("No permissions found for " + pkg, packageInfo.requestedPermissions);
 
-        for (UsesPermissionInfo permInfo : packageInfo.usesPermissions) {
-            final String permission = permInfo.getPermission();
+        for (String permission : packageInfo.requestedPermissions) {
             Log.d(LOG_TAG, "SHELL as " + pkg + " uses permission " + permission);
             assertFalse("SHELL as " + pkg + " contains the illegal permission " + permission,
                     blacklist.contains(permission));
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 2292392..c2aa5fe 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -2286,7 +2286,7 @@
     <!-- Allows an application to start activities from background
          @hide -->
     <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
-        android:protectionLevel="signature|privileged|vendorPrivileged|oem" />
+        android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
 
     <!-- @SystemApi Must be required by activities that handle the intent action
          {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
@@ -4410,9 +4410,9 @@
     <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- A subclass of {@link android.app.SmsAppService} must be protected with this permission. -->
-    <permission android:name="android.permission.BIND_SMS_APP_SERVICE"
-        android:protectionLevel="signature" />
+    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission. -->
+    <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
+                android:protectionLevel="signature" />
 
     <!-- @hide Permission that allows background clipboard access.
          <p>Not for use by third-party applications. -->
diff --git a/tests/tests/preference/Android.bp b/tests/tests/preference/Android.bp
new file mode 100644
index 0000000..23b3224
--- /dev/null
+++ b/tests/tests/preference/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2010 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: "CtsPreferenceTestCases",
+    defaults: ["cts_defaults"],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+
+    static_libs: ["ctstestrunner"],
+
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+
+    srcs: ["src/**/*.java"],
+
+    sdk_version: "test_current",
+}
diff --git a/tests/tests/preference/Android.mk b/tests/tests/preference/Android.mk
deleted file mode 100644
index 5398722..0000000
--- a/tests/tests/preference/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2010 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 := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsPreferenceTestCases
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/preference/AndroidTest.xml b/tests/tests/preference/AndroidTest.xml
index 4287b76..1980c38 100644
--- a/tests/tests/preference/AndroidTest.xml
+++ b/tests/tests/preference/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <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="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/preference/OWNERS b/tests/tests/preference/OWNERS
index d20511f..827134e 100644
--- a/tests/tests/preference/OWNERS
+++ b/tests/tests/preference/OWNERS
@@ -1,2 +1,3 @@
+lpf@google.com
 pavlis@google.com
 clarabayarri@google.com
diff --git a/tests/tests/preference2/Android.bp b/tests/tests/preference2/Android.bp
new file mode 100644
index 0000000..51e446f
--- /dev/null
+++ b/tests/tests/preference2/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2012 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: "CtsPreference2TestCases",
+    defaults: ["cts_defaults"],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+
+    static_libs: [
+        "ctstestrunner",
+        "compatibility-device-util",
+        "mockito-target-minus-junit4",
+        "ub-uiautomator",
+    ],
+
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+
+    srcs: ["src/**/*.java"],
+
+    sdk_version: "test_current",
+}
diff --git a/tests/tests/preference2/Android.mk b/tests/tests/preference2/Android.mk
deleted file mode 100644
index 8fc5ee2..0000000
--- a/tests/tests/preference2/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2012 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 := CtsPreference2TestCases
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctstestrunner \
-    compatibility-device-util \
-    mockito-target-minus-junit4 \
-    ub-uiautomator
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/preference2/AndroidTest.xml b/tests/tests/preference2/AndroidTest.xml
index a3fb234..452702d 100644
--- a/tests/tests/preference2/AndroidTest.xml
+++ b/tests/tests/preference2/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <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" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsPreference2TestCases.apk" />
diff --git a/tests/tests/preference2/OWNERS b/tests/tests/preference2/OWNERS
new file mode 100644
index 0000000..827134e
--- /dev/null
+++ b/tests/tests/preference2/OWNERS
@@ -0,0 +1,3 @@
+lpf@google.com
+pavlis@google.com
+clarabayarri@google.com
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java b/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java
index 2d15765..d4ac9a3 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java
@@ -18,6 +18,8 @@
 
 import static android.provider.cts.MediaStoreTest.TAG;
 import static android.provider.cts.ProviderTestUtils.containsId;
+import static android.provider.cts.ProviderTestUtils.getRawFile;
+import static android.provider.cts.ProviderTestUtils.getRawFileHash;
 import static android.provider.cts.ProviderTestUtils.hash;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -55,7 +57,6 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 @RunWith(Parameterized.class)
 public class MediaStorePendingTest {
@@ -425,27 +426,4 @@
             return session.publish();
         }
     }
-
-    private static File getRawFile(Uri uri) throws Exception {
-        final String res = ProviderTestUtils.executeShellCommand(
-                "content query --uri " + uri + " --projection _data",
-                InstrumentationRegistry.getInstrumentation().getUiAutomation());
-        final int i = res.indexOf("_data=");
-        if (i >= 0) {
-            return new File(res.substring(i + 6));
-        } else {
-            throw new FileNotFoundException("Failed to find _data for " + uri + "; found " + res);
-        }
-    }
-
-    private static String getRawFileHash(File file) throws Exception {
-        final String res = ProviderTestUtils.executeShellCommand(
-                "sha1sum " + file.getAbsolutePath(),
-                InstrumentationRegistry.getInstrumentation().getUiAutomation());
-        if (Pattern.matches("[0-9a-fA-F]{40}.+", res)) {
-            return res.substring(0, 40);
-        } else {
-            throw new FileNotFoundException("Failed to find hash for " + file + "; found " + res);
-        }
-    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStorePlacementTest.java b/tests/tests/provider/src/android/provider/cts/MediaStorePlacementTest.java
new file mode 100644
index 0000000..2259a44
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MediaStorePlacementTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.provider.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.provider.MediaStore.MediaColumns;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+import android.util.Pair;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.io.File;
+
+@RunWith(Parameterized.class)
+public class MediaStorePlacementTest {
+    static final String TAG = "MediaStorePlacementTest";
+
+    private Context mContext;
+    private ContentResolver mContentResolver;
+
+    private Uri mExternalImages;
+
+    @Parameter(0)
+    public String mVolumeName;
+
+    @Parameters
+    public static Iterable<? extends Object> data() {
+        return ProviderTestUtils.getSharedVolumeNames();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
+
+        Log.d(TAG, "Using volume " + mVolumeName);
+        mExternalImages = MediaStore.Images.Media.getContentUri(mVolumeName);
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        final Uri uri = ProviderTestUtils.stageMedia(R.drawable.scenery,
+                mExternalImages, "image/jpeg");
+
+        // By default placed under "Pictures" with sane name
+        final File before = ProviderTestUtils.getRelativeFile(uri);
+        assertTrue(before.getName().startsWith("cts"));
+        assertTrue(before.getName().endsWith("jpg"));
+        assertEquals("Pictures", before.getParent());
+    }
+
+    @Test
+    public void testIgnored() throws Exception {
+        final Uri uri = ProviderTestUtils.stageMedia(R.drawable.scenery,
+                mExternalImages, "image/jpeg");
+
+        {
+            final ContentValues values = new ContentValues();
+            values.put(MediaColumns.SIZE, 0);
+            assertEquals(0, mContentResolver.update(uri, values, null, null));
+        }
+
+        // Make sure shady paths can't be passed in
+        for (String column : new String[] {
+                MediaColumns.DISPLAY_NAME,
+                MediaColumns.PRIMARY_DIRECTORY,
+                MediaColumns.SECONDARY_DIRECTORY
+        }) {
+            final ContentValues values = new ContentValues();
+            values.put(column, "path/to/file");
+            try {
+                mContentResolver.update(uri, values, null, null);
+                fail();
+            } catch (IllegalArgumentException expected) {
+            }
+        }
+    }
+
+    @Test
+    public void testDisplayName_SameMime() throws Exception {
+        final Uri uri = ProviderTestUtils.stageMedia(R.drawable.scenery,
+                mExternalImages, "image/jpeg");
+
+        // Movement within same MIME type is okay
+        final File before = ProviderTestUtils.getRelativeFile(uri);
+        final String name = "CTS" +  System.nanoTime() + ".JPEG";
+        assertTrue(updatePlacement(uri, Pair.create(MediaColumns.DISPLAY_NAME, name)));
+
+        final File after = ProviderTestUtils.getRelativeFile(uri);
+        assertEquals(before.getParent(), after.getParent());
+        assertEquals(name, after.getName());
+    }
+
+    @Test
+    public void testDisplayName_DifferentMime() throws Exception {
+        final Uri uri = ProviderTestUtils.stageMedia(R.drawable.scenery,
+                mExternalImages, "image/jpeg");
+
+        final File before = ProviderTestUtils.getRelativeFile(uri);
+        assertTrue(before.getName().endsWith(".jpg"));
+
+        // Movement across MIME types is not okay; verify that original MIME
+        // type remains intact
+        final String name = "cts" +  System.nanoTime() + ".png";
+        assertTrue(updatePlacement(uri, Pair.create(MediaColumns.DISPLAY_NAME, name)));
+
+        final File after = ProviderTestUtils.getRelativeFile(uri);
+        assertTrue(after.getName().startsWith(name));
+        assertTrue(after.getName().endsWith(".jpg"));
+    }
+
+    @Test
+    public void testDirectory_Valid() throws Exception {
+        final Uri uri = ProviderTestUtils.stageMedia(R.drawable.scenery,
+                mExternalImages, "image/jpeg");
+
+        final File before = ProviderTestUtils.getRelativeFile(uri);
+        assertEquals("Pictures", before.getParent());
+
+        {
+            assertTrue(updatePlacement(uri,
+                    Pair.create(MediaColumns.PRIMARY_DIRECTORY, null)));
+            final File after = ProviderTestUtils.getRelativeFile(uri);
+            assertEquals("Pictures", after.getParent());
+        }
+        {
+            assertTrue(updatePlacement(uri,
+                    Pair.create(MediaColumns.PRIMARY_DIRECTORY, Environment.DIRECTORY_DCIM),
+                    Pair.create(MediaColumns.SECONDARY_DIRECTORY, "Vacation")));
+            final File after = ProviderTestUtils.getRelativeFile(uri);
+            assertEquals("DCIM/Vacation", after.getParent());
+        }
+        {
+            assertTrue(updatePlacement(uri,
+                    Pair.create(MediaColumns.SECONDARY_DIRECTORY, "Misc")));
+            final File after = ProviderTestUtils.getRelativeFile(uri);
+            assertEquals("DCIM/Misc", after.getParent());
+        }
+        {
+            assertTrue(updatePlacement(uri,
+                    Pair.create(MediaColumns.PRIMARY_DIRECTORY, Environment.DIRECTORY_PICTURES)));
+            final File after = ProviderTestUtils.getRelativeFile(uri);
+            assertEquals("Pictures/Misc", after.getParent());
+        }
+        {
+            assertTrue(updatePlacement(uri,
+                    Pair.create(MediaColumns.SECONDARY_DIRECTORY, null)));
+            final File after = ProviderTestUtils.getRelativeFile(uri);
+            assertEquals("Pictures", after.getParent());
+        }
+    }
+
+    @Test
+    public void testDirectory_Invalid() throws Exception {
+        final Uri uri = ProviderTestUtils.stageMedia(R.drawable.scenery,
+                mExternalImages, "image/jpeg");
+
+        assertFalse(updatePlacement(uri,
+                Pair.create(MediaColumns.PRIMARY_DIRECTORY, "Random")));
+        assertFalse(updatePlacement(uri,
+                Pair.create(MediaColumns.PRIMARY_DIRECTORY, Environment.DIRECTORY_ALARMS)));
+    }
+
+    private boolean updatePlacement(Uri uri, Pair<?, ?>... args) throws Exception {
+        final ContentValues values = new ContentValues();
+        for (Pair<?, ?> arg : args) {
+            if (arg.second != null) {
+                values.put(String.valueOf(arg.first), String.valueOf(arg.second));
+            } else {
+                values.putNull(String.valueOf(arg.first));
+            }
+        }
+        try {
+            return (mContentResolver.update(uri, values, null, null) == 1);
+        } catch (Exception tolerated) {
+            return false;
+        }
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
index 4f0850a..45e4e5a 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
@@ -18,7 +18,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -36,8 +35,6 @@
 import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
-import libcore.util.HexEncoding;
-
 import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
@@ -48,8 +45,6 @@
 import org.junit.runners.Parameterized.Parameters;
 
 import java.io.File;
-import java.io.OutputStream;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.UUID;
@@ -197,34 +192,6 @@
         }
     }
 
-    @Test
-    public void testHash() throws Exception {
-        final ContentResolver resolver = getContext().getContentResolver();
-
-        final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis, mExternalImages);
-        SystemClock.sleep(500);
-
-        final String expected = Arrays
-                .toString(HexEncoding.decode("dd41258ce8d306163f3b727603cb064be81973db"));
-
-        // We can force hash to be generated by requesting canonicalization
-        resolver.canonicalize(uri);
-        try (Cursor c = resolver.query(uri, new String[] { MediaColumns.HASH }, null, null)) {
-            assertTrue(c.moveToFirst());
-            assertEquals(expected, Arrays.toString(c.getBlob(0)));
-        }
-
-        // Make sure that editing image results in a different hash
-        try (OutputStream out = resolver.openOutputStream(uri, "wa")) {
-            out.write(42);
-        }
-        SystemClock.sleep(500);
-        try (Cursor c = resolver.query(uri, new String[] { MediaColumns.HASH }, null, null)) {
-            assertTrue(c.moveToFirst());
-            assertNotEquals(expected, Arrays.toString(c.getBlob(0)));
-        }
-    }
-
     private long getExternalPackageSize() throws Exception {
         final StorageManager storage = getContext().getSystemService(StorageManager.class);
         final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreTrashTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreTrashTest.java
deleted file mode 100644
index 97cd1ff..0000000
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreTrashTest.java
+++ /dev/null
@@ -1,151 +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.
- */
-
-package android.provider.cts;
-
-import static android.provider.cts.MediaStoreTest.TAG;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.SystemClock;
-import android.provider.MediaStore;
-import android.provider.MediaStore.MediaColumns;
-import android.support.test.InstrumentationRegistry;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class MediaStoreTrashTest {
-    private Context mContext;
-    private ContentResolver mResolver;
-
-    private Uri mExternalImages;
-
-    @Parameter(0)
-    public String mVolumeName;
-
-    @Parameters
-    public static Iterable<? extends Object> data() {
-        return ProviderTestUtils.getSharedVolumeNames();
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        mContext = InstrumentationRegistry.getTargetContext();
-        mResolver = mContext.getContentResolver();
-
-        Log.d(TAG, "Using volume " + mVolumeName);
-        mExternalImages = MediaStore.Images.Media.getContentUri(mVolumeName);
-    }
-
-    @Test
-    public void testTrashUntrash() throws Exception {
-        final Uri insertUri = mExternalImages;
-        final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis, insertUri);
-        final long id = ContentUris.parseId(uri);
-
-        // Default is not trashed, and no expiration date
-        try (Cursor c = mResolver.query(uri,
-                new String[] { MediaColumns.IS_TRASHED, MediaColumns.DATE_EXPIRES }, null, null)) {
-            assertTrue(c.moveToFirst());
-            assertEquals(0, c.getInt(0));
-            assertTrue(c.isNull(1));
-        }
-        assertTrue(containsId(insertUri, id));
-        assertTrue(containsId(MediaStore.setIncludeTrashed(insertUri), id));
-
-        // Trash should expire roughly 2 days from now
-        MediaStore.trash(mContext, uri);
-        try (Cursor c = mResolver.query(uri,
-                new String[] { MediaColumns.IS_TRASHED, MediaColumns.DATE_EXPIRES }, null, null)) {
-            assertTrue(c.moveToFirst());
-            assertEquals(1, c.getInt(0));
-            assertMostlyEquals((System.currentTimeMillis() + (2 * DateUtils.DAY_IN_MILLIS)) / 1000,
-                    c.getLong(1), 30);
-        }
-        assertFalse(containsId(insertUri, id));
-        assertTrue(containsId(MediaStore.setIncludeTrashed(insertUri), id));
-
-        // Untrash should bring us back
-        MediaStore.untrash(mContext, uri);
-        try (Cursor c = mResolver.query(uri,
-                new String[] { MediaColumns.IS_TRASHED, MediaColumns.DATE_EXPIRES }, null, null)) {
-            assertTrue(c.moveToFirst());
-            assertEquals(0, c.getInt(0));
-            assertTrue(c.isNull(1));
-        }
-        assertTrue(containsId(insertUri, id));
-        assertTrue(containsId(MediaStore.setIncludeTrashed(insertUri), id));
-    }
-
-    @Test
-    public void testTrashExecutes() throws Exception {
-        final Uri insertUri = mExternalImages;
-        final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis, insertUri);
-
-        MediaStore.trash(mContext, uri, 1);
-
-        // Force idle maintenance to run
-        ProviderTestUtils.executeShellCommand(
-                "cmd jobscheduler run -f com.android.providers.media -200",
-                InstrumentationRegistry.getInstrumentation().getUiAutomation());
-
-        // Wait around for item to be deleted
-        final long timeout = SystemClock.elapsedRealtime() + DateUtils.MINUTE_IN_MILLIS;
-        while (SystemClock.elapsedRealtime() < timeout) {
-            try (Cursor c = mResolver.query(uri, null, null, null)) {
-                Log.v(TAG, "Count " + c.getCount());
-                if (c.getCount() == 0) {
-                    return;
-                }
-            }
-            SystemClock.sleep(500);
-        }
-
-        fail("Timed out waiting for job to delete trashed item");
-    }
-
-    private boolean containsId(Uri uri, long id) {
-        try (Cursor c = mResolver.query(uri,
-                new String[] { MediaColumns._ID }, null, null)) {
-            while (c.moveToNext()) {
-                if (c.getLong(0) == id) return true;
-            }
-        }
-        return false;
-    }
-
-    private static void assertMostlyEquals(long expected, long actual, long delta) {
-        if (Math.abs(expected - actual) > delta) {
-            fail("Expected roughly " + expected + " but was " + actual);
-        }
-    }
-}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
index de1b40a..24f7ed4 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
@@ -44,12 +44,14 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -148,6 +150,58 @@
     }
 
     @Test
+    public void testInsertDownload() throws Exception {
+        final String content = "<html><body>Content</body></html>";
+        final String displayName = "cts" + System.nanoTime();
+        final String mimeType = "text/html";
+        final Uri downloadUri = Uri.parse("https://developer.android.com/overview.html");
+        final Uri refererUri = Uri.parse("https://www.android.com");
+
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                Downloads.EXTERNAL_CONTENT_URI, displayName, mimeType);
+        params.setDownloadUri(downloadUri);
+        params.setRefererUri(refererUri);
+
+        final Uri pendingUri = MediaStore.createPending(mContext, params);
+        assertNotNull(pendingUri);
+        mAddedUris.add(pendingUri);
+        final Uri publishUri;
+        try (MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri)) {
+            try (PrintWriter pw = new PrintWriter(session.openOutputStream())) {
+                pw.print(content);
+            }
+            try (OutputStream out = session.openOutputStream()) {
+                out.write(content.getBytes(StandardCharsets.UTF_8));
+            }
+            publishUri = session.publish();
+        }
+
+        try (Cursor cursor = mContentResolver.query(publishUri, null, null, null, null)) {
+            assertEquals(1, cursor.getCount());
+
+            cursor.moveToNext();
+            assertEquals(mimeType,
+                    cursor.getString(cursor.getColumnIndex(Downloads.MIME_TYPE)));
+            assertEquals(displayName,
+                    cursor.getString(cursor.getColumnIndex(Downloads.DISPLAY_NAME)));
+            assertEquals(downloadUri.toString(),
+                    cursor.getString(cursor.getColumnIndex(Downloads.DOWNLOAD_URI)));
+            assertEquals(refererUri.toString(),
+                    cursor.getString(cursor.getColumnIndex(Downloads.REFERER_URI)));
+        }
+
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        try (InputStream in = mContentResolver.openInputStream(publishUri)) {
+            final byte[] buf = new byte[512];
+            int bytesRead;
+            while ((bytesRead = in.read(buf)) != -1) {
+                actual.write(buf, 0, bytesRead);
+            }
+        }
+        assertEquals(content, actual.toString(StandardCharsets.UTF_8.name()));
+    }
+
+    @Test
     public void testUpdateDownload() throws Exception {
         final String displayName = "cts" + System.nanoTime();
         final MediaStore.PendingParams params = new MediaStore.PendingParams(
@@ -268,7 +322,7 @@
     private Uri insertImage(String displayName, String description,
             File file, String mimeType, int resourceId) throws Exception {
         file.createNewFile();
-        try (InputStream in = mContext.getResources().openRawResource(R.raw.scenery);
+        try (InputStream in = mContext.getResources().openRawResource(resourceId);
              OutputStream out = new FileOutputStream(file)) {
             FileUtils.copy(in, out);
         }
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index c5c43f4..825cdc3 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -68,6 +68,9 @@
     private static final Pattern BMGR_ENABLED_PATTERN = Pattern.compile(
             "^Backup Manager currently (enabled|disabled)$");
 
+    private static final Pattern PATTERN_STORAGE_PATH = Pattern.compile(
+            "(?i)^/storage/[^/]+/(?:[0-9]+/)?");
+
     static Iterable<String> getSharedVolumeNames() {
         if (StorageManager.hasIsolatedStorage()) {
             final Set<String> volumeNames = MediaStore
@@ -315,4 +318,37 @@
         }
         return false;
     }
+
+    public static File getRawFile(Uri uri) throws Exception {
+        final String res = ProviderTestUtils.executeShellCommand(
+                "content query --uri " + uri + " --projection _data",
+                InstrumentationRegistry.getInstrumentation().getUiAutomation());
+        final int i = res.indexOf("_data=");
+        if (i >= 0) {
+            return new File(res.substring(i + 6));
+        } else {
+            throw new FileNotFoundException("Failed to find _data for " + uri + "; found " + res);
+        }
+    }
+
+    public static String getRawFileHash(File file) throws Exception {
+        final String res = ProviderTestUtils.executeShellCommand(
+                "sha1sum " + file.getAbsolutePath(),
+                InstrumentationRegistry.getInstrumentation().getUiAutomation());
+        if (Pattern.matches("[0-9a-fA-F]{40}.+", res)) {
+            return res.substring(0, 40);
+        } else {
+            throw new FileNotFoundException("Failed to find hash for " + file + "; found " + res);
+        }
+    }
+
+    public static File getRelativeFile(Uri uri) throws Exception {
+        final String path = getRawFile(uri).getAbsolutePath();
+        final Matcher matcher = PATTERN_STORAGE_PATH.matcher(path);
+        if (matcher.find()) {
+            return new File(path.substring(matcher.end()));
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
 }
diff --git a/tests/tests/role/AndroidTest.xml b/tests/tests/role/AndroidTest.xml
index 8adcbc1..bdc6e71 100644
--- a/tests/tests/role/AndroidTest.xml
+++ b/tests/tests/role/AndroidTest.xml
@@ -20,6 +20,8 @@
 
     <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_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" />
diff --git a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
index 03f9513..7f096cc 100644
--- a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
+++ b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
@@ -38,14 +38,6 @@
                 <data android:scheme="tel" />
             </intent-filter>
         </activity>
-        <service
-            android:name=".DialerInCallService"
-            android:permission="android.permission.BIND_INCALL_SERVICE">
-            <intent-filter>
-                <action android:name="android.telecom.InCallService" />
-            </intent-filter>
-            <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
-        </service>
 
         <!-- Sms -->
         <activity android:name=".SmsSendToActivity">
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 9613c15..13caf39 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -206,7 +206,7 @@
         boolean[] successful = new boolean[1];
         CountDownLatch latch = new CountDownLatch(1);
         runWithShellPermissionIdentity(() -> sRoleManager.addRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         successful[0] = true;
@@ -229,7 +229,7 @@
         boolean[] successful = new boolean[1];
         CountDownLatch latch = new CountDownLatch(1);
         runWithShellPermissionIdentity(() -> sRoleManager.removeRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         successful[0] = true;
diff --git a/tests/tests/sax/AndroidTest.xml b/tests/tests/sax/AndroidTest.xml
index f81aa67..a9c5ba7 100644
--- a/tests/tests/sax/AndroidTest.xml
+++ b/tests/tests/sax/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS SAX test cases">
     <option name="test-suite-tag" value="cts" />
     <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="not_instant_app" />
     <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/shortcutmanager/AndroidTest.xml b/tests/tests/shortcutmanager/AndroidTest.xml
index f2f6a46..512330b 100644
--- a/tests/tests/shortcutmanager/AndroidTest.xml
+++ b/tests/tests/shortcutmanager/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <!-- 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" />
     <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/telecom/CallScreeningServiceTestApp/Android.mk b/tests/tests/telecom/CallScreeningServiceTestApp/Android.mk
index 9f140ef..ae09720 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/Android.mk
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/Android.mk
@@ -22,11 +22,11 @@
 
 src_dirs := src
 
+LOCAL_AIDL_INCLUDES := $(call all-Iaidl-files-under, aidl)
+
 LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs)) \
                    $(call all-Iaidl-files-under, aidl)
 
-LOCAL_AIDL_INCLUDES := aidl/
-
 LOCAL_PACKAGE_NAME := CallScreeningServiceTestApp
 
 LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
index c3b39a7..9dd60be6 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
@@ -30,5 +30,10 @@
                 <action android:name="android.telecom.cts.screeningtestapp.ACTION_CONTROL_CALL_SCREENING_SERVICE" />
             </intent-filter>
         </service>
+        <receiver android:name=".NuisanceCallStateReceiver">
+            <intent-filter>
+                <action android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" />
+            </intent-filter>
+        </receiver>
     </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 43c75df..62640d6 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
@@ -26,4 +26,10 @@
             in Icon icon, int confidence);
     void setCallResponse(boolean shouldDisallowCall, boolean shouldRejectCall,
             boolean shouldSkipCallLog, boolean shouldSkipNotification);
+    void waitForNuisanceReport(long timeoutMillis);
+    boolean getIsNuisance();
+    Uri getNuisanceCallHandle();
+    int getNuisanceCallType();
+    int getNuisanceCallDuration();
+    boolean isNuisanceReportReceived();
 }
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 1563fb5..0e9e913 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
@@ -20,13 +20,18 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
+import android.net.Uri;
 import android.os.IBinder;
 import android.telecom.CallIdentification;
 import android.telecom.CallScreeningService;
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 public class CallScreeningServiceControl extends Service {
+    private static final int ASYNC_TIMEOUT = 10000;
     private static final String TAG = CallScreeningServiceControl.class.getSimpleName();
     public static final String CONTROL_INTERFACE_ACTION =
             "android.telecom.cts.screeningtestapp.ACTION_CONTROL_CALL_SCREENING_SERVICE";
@@ -41,6 +46,8 @@
                 @Override
                 public void reset() {
                     mCallIdentification = null;
+                    mNuisanceCallUri = null;
+                    mIsNuisanceReportReceived = false;
                     mCallResponse = new CallScreeningService.CallResponse.Builder()
                             .setDisallowCall(false)
                             .setRejectCall(false)
@@ -79,10 +86,43 @@
                             .setRejectCall(shouldRejectCall)
                             .build();
                 }
+
+                @Override
+                public void waitForNuisanceReport(long timeoutMillis) {
+                    try {
+                        mNuisanceLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+
+                @Override
+                public boolean getIsNuisance() {
+                    return mIsNuisanceCall;
+                }
+
+                @Override
+                public Uri getNuisanceCallHandle() {
+                    return mNuisanceCallUri;
+                }
+
+                @Override
+                public int getNuisanceCallType() {
+                    return mNuisanceCallType;
+                }
+
+                @Override
+                public int getNuisanceCallDuration() {
+                    return mNuisanceCallDuration;
+                }
+
+                @Override
+                public boolean isNuisanceReportReceived() {
+                    return mIsNuisanceReportReceived;
+                }
             };
 
     private CallIdentification mCallIdentification = null;
-    private boolean mIsAcceptingCall = true;
     private CallScreeningService.CallResponse mCallResponse =
             new CallScreeningService.CallResponse.Builder()
                     .setDisallowCall(false)
@@ -90,6 +130,12 @@
                     .setSkipCallLog(false)
                     .setSkipNotification(false)
                     .build();
+    private CountDownLatch mNuisanceLatch = new CountDownLatch(1);
+    private boolean mIsNuisanceCall;
+    private int mNuisanceCallType;
+    private int mNuisanceCallDuration;
+    private Uri mNuisanceCallUri;
+    private boolean mIsNuisanceReportReceived = false;
 
     public static CallScreeningServiceControl getInstance() {
         return sCallScreeningServiceControl;
@@ -119,4 +165,16 @@
     public CallScreeningService.CallResponse getCallResponse() {
         return mCallResponse;
     }
+
+    public void handleNuisanceStatusChanged(Uri handle, int callDuration, int callType,
+            boolean isNuisance) {
+        mNuisanceCallUri = handle;
+        mIsNuisanceCall = isNuisance;
+        mNuisanceCallDuration = callDuration;
+        mNuisanceCallType = callType;
+        mIsNuisanceReportReceived = true;
+        Log.i(TAG, "handleNuisanceStatusChanged - got nuisance report");
+        mNuisanceLatch.countDown();
+    }
+
 }
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/NuisanceCallStateReceiver.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/NuisanceCallStateReceiver.java
new file mode 100644
index 0000000..1d393f4
--- /dev/null
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/NuisanceCallStateReceiver.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.telecom.cts.screeningtestapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.telecom.CallScreeningService;
+import android.util.Log;
+
+public class NuisanceCallStateReceiver extends BroadcastReceiver {
+    private static String TAG = "NuisanceCallStateReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent.getAction().equals(CallScreeningService.ACTION_NUISANCE_CALL_STATUS_CHANGED)) {
+            int callDuration = intent.getIntExtra(CallScreeningService.EXTRA_CALL_DURATION, -1);
+            Uri handle = intent.getParcelableExtra(CallScreeningService.EXTRA_CALL_HANDLE);
+            int callType = intent.getIntExtra(CallScreeningService.EXTRA_CALL_TYPE, -1);
+            boolean isNuisance = intent.getBooleanExtra(CallScreeningService.EXTRA_IS_NUISANCE,
+                    false);
+
+            Log.i(TAG, "onReceive - got nuisance report");
+            CallScreeningServiceControl.getInstance().handleNuisanceStatusChanged(handle,
+                    callDuration, callType, isNuisance);
+        }
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index a6d9fc1..7472e48 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -695,7 +695,7 @@
      * @return Randomized phone number.
      */
     Uri createRandomTestNumber() {
-        return Uri.fromParts("tel", String.format("%06d", new Random().nextInt(999999))
+        return Uri.fromParts("tel", String.format("16%05d", new Random().nextInt(99999))
                 + String.format("%04d", new Random().nextInt(9999)), null);
     }
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
index 9e131ae..cd4d5f8 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -678,6 +678,19 @@
     }
 
     /**
+     * Tests whether the getCallDirection() getter returns correct call direction.
+     */
+    public void testGetCallDirection() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        assertEquals(Call.Details.DIRECTION_OUTGOING, mCall.getDetails().getCallDirection());
+        assertFalse(Call.Details.DIRECTION_INCOMING == mCall.getDetails().getCallDirection());
+        assertFalse(Call.Details.DIRECTION_UNKNOWN == mCall.getDetails().getCallDirection());
+    }
+
+    /**
      * Asserts that a call's extras contain a specified key.
      *
      * @param call The call.
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index d3e0958..6f09886 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -53,7 +53,7 @@
     private static final String TEST_APP_PACKAGE = "android.telecom.cts.redirectiontestapp";
     private static final String TEST_APP_COMPONENT = TEST_APP_PACKAGE
                     + "/android.telecom.cts.redirectiontestapp.CtsCallRedirectionService";
-    private static final String ROLE_CALL_REDIRECTION = "android.app.role.PROXY_CALLING_APP";
+    private static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
 
     private static final Uri SAMPLE_HANDLE = Uri.fromParts(PhoneAccount.SCHEME_TEL, "0001112222",
             null);
@@ -180,7 +180,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
@@ -209,7 +209,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index fede567..c1de6a0 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -18,6 +18,8 @@
 
 import static android.telecom.cts.TestUtils.*;
 
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
 import android.os.Bundle;
 import android.telecom.Call;
 import android.telecom.Conference;
@@ -34,6 +36,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Extended suite of tests that use {@link CtsConnectionService} and {@link MockInCallService} to
@@ -87,6 +91,17 @@
         assertConnectionState(mConferenceObject.getConnections().get(0), Connection.STATE_ACTIVE);
         assertConnectionState(mConferenceObject.getConnections().get(1), Connection.STATE_ACTIVE);
         assertConferenceState(mConferenceObject, Connection.STATE_ACTIVE);
+
+        LinkedBlockingQueue<Connection> queue = new LinkedBlockingQueue(1);
+        runWithShellPermissionIdentity(() ->
+                queue.put(mConferenceObject.getPrimaryConnection()));
+        try {
+            Connection primaryConnection = queue.poll(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                    TimeUnit.MILLISECONDS);
+            assertEquals(mConferenceObject.getConnections().get(0), primaryConnection);
+        } catch (InterruptedException e) {
+            fail("Couldn't get TTY mode.");
+        }
     }
 
     public void testConferenceSplit() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
index 27a7010..7cd2b13 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
@@ -43,8 +43,8 @@
 public class CtsRoleManagerAdapter {
 
     private static final String TAG = CtsRoleManagerAdapter.class.getSimpleName();
-    private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
-    private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+    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";
@@ -163,7 +163,7 @@
         Executor executor = mContext.getMainExecutor();
         LinkedBlockingQueue<String> q = new LinkedBlockingQueue<>(1);
         runWithShellPermissionIdentity(() -> {
-            mRoleManager.addRoleHolderAsUser(roleName, packageName, user, executor,
+            mRoleManager.addRoleHolderAsUser(roleName, packageName, 0, user, executor,
                     new RoleManagerCallback() {
                         @Override
                         public void onSuccess() {
@@ -186,7 +186,7 @@
         Executor executor = mContext.getMainExecutor();
         LinkedBlockingQueue<String> q = new LinkedBlockingQueue<>(1);
         runWithShellPermissionIdentity(() -> {
-            mRoleManager.removeRoleHolderAsUser(roleName, packageName, user, executor,
+            mRoleManager.removeRoleHolderAsUser(roleName, packageName, 0, user, executor,
                     new RoleManagerCallback() {
                         @Override
                         public void onSuccess() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/DefaultPhoneAccountTest.java b/tests/tests/telecom/src/android/telecom/cts/DefaultPhoneAccountTest.java
index 9d73e43..6a84634 100755
--- a/tests/tests/telecom/src/android/telecom/cts/DefaultPhoneAccountTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DefaultPhoneAccountTest.java
@@ -16,6 +16,8 @@
 
 package android.telecom.cts;
 
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -58,6 +60,33 @@
     }
 
     /**
+     * Verifies that {@link TelecomManager#getUserSelectedOutgoingPhoneAccount()} is able to
+     * retrieve the user-selected outgoing phone account.
+     * Given that there is a user-selected default, also verifies that
+     * {@link TelecomManager#getDefaultOutgoingPhoneAccount(String)} reports this value as well.
+     * @throws Exception
+     */
+    public void testSetUserSelectedOutgoingPhoneAccount() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        // Make sure to set the default outgoing phone account to the new connection service
+        setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+
+        // Use TelecomManager API to set the outgoing phone account.
+        runWithShellPermissionIdentity(() ->
+                mTelecomManager.setUserSelectedOutgoingPhoneAccount(
+                        TestUtils.TEST_PHONE_ACCOUNT_HANDLE));
+
+        PhoneAccountHandle handle = mTelecomManager.getUserSelectedOutgoingPhoneAccount();
+        assertEquals(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, handle);
+
+        PhoneAccountHandle defaultOutgoing = mTelecomManager.getDefaultOutgoingPhoneAccount(
+                PhoneAccount.SCHEME_TEL);
+        assertEquals(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, defaultOutgoing);
+    }
+
+    /**
      * Verifies operation of the {@link TelecomManager#getDefaultOutgoingPhoneAccount(String)} API
      * where there is NO user selected default outgoing phone account.
      * In AOSP, this mimics the user having changed the
diff --git a/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java b/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
new file mode 100644
index 0000000..2247cdd
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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 static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import android.telecom.TelecomManager;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class TelecomManagerTest extends BaseTelecomTestWithMockServices {
+    public void testGetCurrentTtyMode() {
+        LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue(1);
+        runWithShellPermissionIdentity(() ->
+                queue.put(mTelecomManager.getCurrentTtyMode()));
+        try {
+            int currentTtyMode = queue.poll(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                    TimeUnit.MILLISECONDS);
+            assertEquals(TelecomManager.TTY_MODE_OFF, currentTtyMode);
+            assertFalse(TelecomManager.TTY_MODE_FULL == currentTtyMode);
+            assertFalse(TelecomManager.TTY_MODE_HCO == currentTtyMode);
+            assertFalse(TelecomManager.TTY_MODE_VCO == currentTtyMode);
+        } catch (InterruptedException e) {
+            fail("Couldn't get TTY mode.");
+            e.printStackTrace();
+        }
+    }
+
+    public void testIsInEmergencyCall() {
+        LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
+        runWithShellPermissionIdentity(() ->
+                queue.put(mTelecomManager.isInEmergencyCall()));
+        try {
+            boolean isInEmergencyCall = queue.poll(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                    TimeUnit.MILLISECONDS);
+            assertFalse(isInEmergencyCall);
+        } catch (InterruptedException e) {
+            fail("Couldn't check if in emergency call.");
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index 38e1a25..e772cc1 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -52,6 +52,7 @@
 public class TestUtils {
     static final String TAG = "TelecomCTSTests";
     static final boolean HAS_TELECOM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+    static final long WAIT_FOR_NUISANCE_REPORT_TIMEOUT_MS = 1000;
     static final long WAIT_FOR_STATE_CHANGE_TIMEOUT_MS = 10000;
     static final long WAIT_FOR_CALL_ADDED_TIMEOUT_S = 15;
     static final long WAIT_FOR_STATE_CHANGE_TIMEOUT_CALLBACK = 50;
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 7d1bae2..f594945 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -47,6 +47,7 @@
 import android.telecom.cts.screeningtestapp.CtsCallScreeningService;
 import android.telecom.cts.screeningtestapp.ICallScreeningControl;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -62,7 +63,7 @@
             "android.telecom.cts.screeningtestapp/"
                     + "android.telecom.cts.screeningtestapp.CtsCallScreeningService";
     private static final int ASYNC_TIMEOUT = 10000;
-    private static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING_APP";
+    private static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
     private static final CallIdentification SAMPLE_CALL_ID = new CallIdentification.Builder()
             .setName("Joe's Laundromat")
             .setDescription("1234 Dirtysocks Lane, Cleanville, USA")
@@ -232,33 +233,7 @@
         if (!shouldTestTelecom(mContext)) {
             return;
         }
-
-        // Tell the test app to set its call id info.
-        mCallScreeningControl.setProviderCallIdentification(
-                SAMPLE_CALL_ID.getName(),
-                SAMPLE_CALL_ID.getDescription(),
-                SAMPLE_CALL_ID.getDetails(),
-                SAMPLE_CALL_ID.getPhoto(),
-                SAMPLE_CALL_ID.getNuisanceConfidence());
-
-        // Setup content observer to notify us when we call log entry is added.
-        CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
-
-        Uri phoneNumber = createRandomTestNumber();
-        Bundle extras = new Bundle();
-        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, phoneNumber);
-        // Create a new outgoing call.
-        placeAndVerifyCall(extras);
-
-        // Wait for call id to be passed back to InCallService
-        assertCallIdentification(SAMPLE_CALL_ID, TEST_APP_NAME, TEST_APP_PACKAGE);
-
-        // Disconnect the call
-        mInCallCallbacks.getService().disconnectAllCalls();
-        assertNumCalls(mInCallCallbacks.getService(), 0);
-
-        // Wait for it to log.
-        callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+        Uri phoneNumber = placeOutgoingCall();
 
         // Query the latest entry into the call log and verify the call identification information
         // was logged appropriately
@@ -310,7 +285,84 @@
         assertEquals(SAMPLE_CALL_ID, unparceled);
     }
 
-    private void addIncomingAndVerifyBlocked() throws Exception {
+    /**
+     * Verifies operation of the {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)} API
+     * for an outgoing call; should not be possible to report as nuisance.
+     * @throws Exception
+     */
+    public void testReportNuisanceInvalid() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+        Uri phoneNumber = placeOutgoingCall();
+
+        // Report the call as a nuisance call.
+        mTelecomManager.reportNuisanceCallStatus(phoneNumber, true);
+
+        // Block on the control service and wait for the nuisance report; we don't expect one so we
+        // will only wait a short time to avoid this test blocking for a long time.
+        mCallScreeningControl.waitForNuisanceReport(TestUtils.WAIT_FOR_NUISANCE_REPORT_TIMEOUT_MS);
+
+        // We should not have gotten a response back.
+        assertFalse(mCallScreeningControl.isNuisanceReportReceived());
+    }
+
+    /**
+     * Verifies operation of the {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)} API
+     * for an incoming call.
+     * @throws Exception
+     */
+    public void testReportNuisanceIncoming() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+        Uri phoneNumber = addIncoming(true /* disconnectImmediately */);
+
+        // Disconnect the incoming call so it can be logged.
+        mInCallCallbacks.getService().disconnectAllCalls();
+        assertNumCalls(mInCallCallbacks.getService(), 0);
+
+        // Report the call as a nuisance call.
+        mTelecomManager.reportNuisanceCallStatus(phoneNumber, true);
+
+        // Block on the control service and wait for the nuisance report; we will potentially wait
+        // longer because we really do expect something here.
+        mCallScreeningControl.waitForNuisanceReport(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+
+        // We should have gotten a response back.
+        assertTrue(mCallScreeningControl.isNuisanceReportReceived());
+    }
+
+    private Uri placeOutgoingCall() throws Exception {
+        // Tell the test app to set its call id info.
+        mCallScreeningControl.setProviderCallIdentification(
+                SAMPLE_CALL_ID.getName(),
+                SAMPLE_CALL_ID.getDescription(),
+                SAMPLE_CALL_ID.getDetails(),
+                SAMPLE_CALL_ID.getPhoto(),
+                SAMPLE_CALL_ID.getNuisanceConfidence());
+
+        // Setup content observer to notify us when we call log entry is added.
+        CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
+
+        Uri phoneNumber = createRandomTestNumber();
+        Bundle extras = new Bundle();
+        extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, phoneNumber);
+        // Create a new outgoing call.
+        placeAndVerifyCall(extras);
+
+        // Wait for call id to be passed back to InCallService
+        assertCallIdentification(SAMPLE_CALL_ID, TEST_APP_NAME, TEST_APP_PACKAGE);
+
+        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 {
         // 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();
@@ -325,8 +377,19 @@
         // Wait until the new incoming call is processed.
         waitOnAllHandlers(getInstrumentation());
 
+        if (disconnectImmediately) {
+            // Disconnect the call
+            mInCallCallbacks.getService().disconnectAllCalls();
+            assertNumCalls(mInCallCallbacks.getService(), 0);
+        }
+
         // Wait for the content observer to report that we have gotten a new call log entry.
         callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+        return testNumber;
+    }
+
+    private void addIncomingAndVerifyBlocked() throws Exception {
+        Uri testNumber = addIncoming(false);
 
         // Query the latest entry into the call log.
         Cursor callsCursor = mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, null,
@@ -360,7 +423,7 @@
                 CallLog.Calls.CONTENT_URI, true,
                 new ContentObserver(mHandler) {
                     @Override
-                    public void onChange(boolean selfChange) {
+                    public void onChange(boolean selfChange, Uri uri) {
                         mContext.getContentResolver().unregisterContentObserver(this);
                         changeLatch.countDown();
                         super.onChange(selfChange);
@@ -454,7 +517,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
@@ -483,7 +546,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
index ef24240..ead51f4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
@@ -45,8 +45,8 @@
 public class ThirdPartyInCallServiceTest extends BaseTelecomTestWithMockServices {
 
     private static final String TAG = ThirdPartyInCallServiceTest.class.getSimpleName();
-    private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
-    private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+    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;
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
index 7b5024b..ee3ff6e 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
@@ -17,24 +17,27 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
 import android.os.Parcel;
 import android.telephony.CellIdentityCdma;
 import android.telephony.CellIdentityGsm;
 import android.telephony.CellIdentityLte;
 import android.telephony.CellIdentityNr;
+import android.telephony.CellIdentityTdscdma;
 import android.telephony.CellIdentityWcdma;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoCdma;
 import android.telephony.CellInfoGsm;
 import android.telephony.CellInfoLte;
 import android.telephony.CellInfoNr;
+import android.telephony.CellInfoTdscdma;
 import android.telephony.CellInfoWcdma;
 import android.telephony.CellSignalStrengthCdma;
 import android.telephony.CellSignalStrengthGsm;
 import android.telephony.CellSignalStrengthLte;
 import android.telephony.CellSignalStrengthNr;
+import android.telephony.CellSignalStrengthTdscdma;
 import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
 import android.util.Log;
@@ -49,8 +52,7 @@
  */
 public class CellInfoTest extends AndroidTestCase{
     private final Object mLock = new Object();
-    private TelephonyManager mTelephonyManager;
-    private static ConnectivityManager mCm;
+    private TelephonyManager mTm;
     private static final String TAG = "android.telephony.cts.CellInfoTest";
     // Maximum and minimum possible RSSI values(in dbm).
     private static final int MAX_RSSI = -10;
@@ -108,8 +110,10 @@
     private static final int LAC = 65535;
     // UMTS Cell Identity ranges from 0 to 268435455.
     private static final int CID_UMTS = 268435455;
-    // Primary Scrambling Coderanges from 0 to 511.
+    // Primary Scrambling Code ranges from 0 to 511.
     private static final int PSC = 511;
+    // Cell Parameters Index rangest from 0-127.
+    private static final int CPID = 127;
 
     // The followings are parameters for testing CellIdentityGsm
     // GSM Cell Identity ranges from 0 to 65535.
@@ -122,30 +126,32 @@
 
     private PackageManager mPm;
 
+    private boolean isCamped() {
+        ServiceState ss = mTm.getServiceState();
+        if (ss == null) return false;
+        return (ss.getState() == ServiceState.STATE_IN_SERVICE
+                || ss.getState() == ServiceState.STATE_EMERGENCY_ONLY);
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mTelephonyManager =
-                (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
-        mCm = (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mTm = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
         mPm = getContext().getPackageManager();
     }
 
     public void testCellInfo() throws Throwable {
 
-        if(! (mPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY))) {
+        if(!(mPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY))) {
             Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
 
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
-            return;
-        }
+        if (!isCamped()) fail("Device is not camped to a cell");
 
         // getAllCellInfo should never return null, and there should
         // be at least one entry.
-        List<CellInfo> allCellInfo = mTelephonyManager.getAllCellInfo();
+        List<CellInfo> allCellInfo = mTm.getAllCellInfo();
         assertNotNull("TelephonyManager.getAllCellInfo() returned NULL!", allCellInfo);
         assertTrue("TelephonyManager.getAllCellInfo() returned zero-length list!",
             allCellInfo.size() > 0);
@@ -163,8 +169,12 @@
                 verifyGsmInfo((CellInfoGsm) cellInfo);
             } else if (cellInfo instanceof CellInfoCdma) {
                 verifyCdmaInfo((CellInfoCdma) cellInfo);
+            } else if (cellInfo instanceof CellInfoTdscdma) {
+                verifyTdscdmaInfo((CellInfoTdscdma) cellInfo);
             } else if (cellInfo instanceof CellInfoNr) {
                 verifyNrInfo((CellInfoNr) cellInfo);
+            } else {
+                fail("Unknown CellInfo Type reported.");
             }
         }
 
@@ -211,11 +221,13 @@
 
         int basestationId = cdma.getBasestationId();
         assertTrue("getBasestationId() out of range [0,65535], basestationId=" + basestationId,
-                basestationId == Integer.MAX_VALUE || (basestationId >= 0 && basestationId <= BASESTATION_ID));
+                basestationId == Integer.MAX_VALUE
+                        || (basestationId >= 0 && basestationId <= BASESTATION_ID));
 
         int longitude = cdma.getLongitude();
         assertTrue("getLongitude() out of range [-2592000,2592000], longitude=" + longitude,
-                longitude == Integer.MAX_VALUE || (longitude >= -LONGITUDE && longitude <= LONGITUDE));
+                longitude == Integer.MAX_VALUE
+                        || (longitude >= -LONGITUDE && longitude <= LONGITUDE));
 
         int latitude = cdma.getLatitude();
         assertTrue("getLatitude() out of range [-1296000,1296000], latitude=" + latitude,
@@ -697,6 +709,103 @@
         assertEquals(gsm, newCss);
     }
 
+    // Verify tdscdma cell information is within correct range.
+    private void verifyTdscdmaInfo(CellInfoTdscdma tdscdma) {
+        verifyCellConnectionStatus(tdscdma.getCellConnectionStatus());
+        verifyCellInfoTdscdmaParcelandHashcode(tdscdma);
+        verifyCellIdentityTdscdma(tdscdma.getCellIdentity());
+        verifyCellIdentityTdscdmaParcel(tdscdma.getCellIdentity());
+        verifyCellSignalStrengthTdscdma(tdscdma.getCellSignalStrength());
+        verifyCellSignalStrengthTdscdmaParcel(tdscdma.getCellSignalStrength());
+    }
+
+    private void verifyCellInfoTdscdmaParcelandHashcode(CellInfoTdscdma tdscdma) {
+        Parcel p = Parcel.obtain();
+        tdscdma.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        CellInfoTdscdma newCi = CellInfoTdscdma.CREATOR.createFromParcel(p);
+        assertTrue(tdscdma.equals(newCi));
+        assertEquals("hashCode() did not get right hasdCode", tdscdma.hashCode(), newCi.hashCode());
+    }
+
+    private void verifyCellIdentityTdscdma(CellIdentityTdscdma tdscdma) {
+        String mccStr = tdscdma.getMccString();
+        String mncStr = tdscdma.getMncString();
+
+        // This class was added after numeric mcc/mncs were no longer provided, so it lacks the
+        // basic getMcc() and getMnc() - Dummy out those checks.
+        verifyPlmnInfo(tdscdma.getMccString(), tdscdma.getMncString(),
+                mccStr != null ? Integer.parseInt(mccStr) : CellInfo.UNAVAILABLE,
+                mncStr != null ? Integer.parseInt(mncStr) : CellInfo.UNAVAILABLE);
+
+        int lac = tdscdma.getLac();
+        assertTrue("getLac() out of range [0, 65535], lac=" + lac,
+                (lac >= 0 && lac <= LAC) || lac == Integer.MAX_VALUE);
+
+        int cid = tdscdma.getCid();
+        assertTrue("getCid() out of range [0, 268435455], cid=" + cid,
+                (cid >= 0 && cid <= CID_UMTS) || cid == Integer.MAX_VALUE);
+
+        // Verify tdscdma primary scrambling code information.
+        // Primary scrambling code should be within [0, 511].
+        int cpid = tdscdma.getCpid();
+        assertTrue("getCpid() out of range [0, 127], cpid=" + cpid, (cpid >= 0 && cpid <= CPID));
+
+        String mobileNetworkOperator = tdscdma.getMobileNetworkOperator();
+        assertTrue("getMobileNetworkOperator() out of range [0, 999999], mobileNetworkOperator="
+                        + mobileNetworkOperator,
+                mobileNetworkOperator == null
+                        || mobileNetworkOperator.matches("^[0-9]{5,6}$"));
+
+        // b/123957505
+        // int uarfcn = tdscdma.getUarfcn();
+        // Reference 3GPP 25.101 Table 5.2
+        // From Appendix E.1, even though UARFCN is numbered from 400, the minumum
+        // usable channel is 412 due to the fixed bandwidth of 5Mhz
+        // assertTrue("getUarfcn() out of range [412,11000], uarfcn=" + uarfcn,
+        //        uarfcn >= 412 && uarfcn <= 11000);
+
+        String alphaLong = (String) tdscdma.getOperatorAlphaLong();
+        assertNotNull("getOperatorAlphaLong() returns NULL!", alphaLong);
+
+        String alphaShort = (String) tdscdma.getOperatorAlphaShort();
+        assertNotNull("getOperatorAlphaShort() returns NULL!", alphaShort);
+    }
+
+    private void verifyCellIdentityTdscdmaParcel(CellIdentityTdscdma tdscdma) {
+        Parcel p = Parcel.obtain();
+        tdscdma.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        CellIdentityTdscdma newci = CellIdentityTdscdma.CREATOR.createFromParcel(p);
+        assertEquals(tdscdma, newci);
+    }
+
+    private void verifyCellSignalStrengthTdscdma(CellSignalStrengthTdscdma tdscdma) {
+        verifyRssiDbm(tdscdma.getDbm());
+
+        // Dbm here does not have specific limits. So just calling to verify that it does not crash
+        // the phone
+        tdscdma.getDbm();
+
+        int asuLevel = tdscdma.getAsuLevel();
+        assertTrue("getLevel() out of range [0,31] (or 99 is unknown), level=" + asuLevel,
+                asuLevel == 99 || (asuLevel >= 0 && asuLevel <= 31));
+
+        int level = tdscdma.getLevel();
+        assertTrue("getLevel() out of range [0,4], level=" + level, level >= 0 && level <= 4);
+    }
+
+    private void verifyCellSignalStrengthTdscdmaParcel(CellSignalStrengthTdscdma tdscdma) {
+        Parcel p = Parcel.obtain();
+        tdscdma.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        CellSignalStrengthTdscdma newCss = CellSignalStrengthTdscdma.CREATOR.createFromParcel(p);
+        assertEquals(tdscdma, newCss);
+    }
+
     // Rssi(in dbm) should be within [MIN_RSSI, MAX_RSSI].
     private void verifyRssiDbm(int dbm) {
         assertTrue("getCellSignalStrength().getDbm() out of range, dbm=" + dbm,
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
index cb87173..a31babf 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
@@ -86,28 +86,38 @@
 
         Set<Class<?>> types = new HashSet<Class<?>>();
 
-        Class<?> type = getSignalStrengthTypeForNetworkType(mTm.getDataNetworkType());
-        if (type != null) types.add(type);
+        Class<?> dataType = getSignalStrengthTypeForNetworkType(mTm.getDataNetworkType());
+        if (dataType != null) types.add(dataType);
 
-        type = getSignalStrengthTypeForNetworkType(mTm.getNetworkType());
-        if (type != null) types.add(type);
+        Class<?> voiceType = getSignalStrengthTypeForNetworkType(mTm.getNetworkType());
 
-        // Blocked by b/123096279
-        /*
+        // Check if camped for Voice-Only
+        if (dataType == null && voiceType != null) {
+            types.add(voiceType);
+        }
+
+        // Check for SRLTE
+        if (dataType != null && voiceType != null
+                && dataType.equals(CellSignalStrengthLte.class)
+                && voiceType.equals(CellSignalStrengthCdma.class)) {
+            types.add(voiceType);
+        }
+
+        // Check for NR
+        if (isUsingEnDc()) {
+            types.add(CellSignalStrengthNr.class);
+        }
+
         for (CellSignalStrength css : signalStrengths) {
             assertTrue("Invalid SignalStrength type detected" + css.getClass(),
-                    types.contains(css.getClass())
-                            || css instanceof CellSignalStrengthNr && isUsingEnDc());
+                    types.contains(css.getClass()));
         }
-        */
     }
 
     /** Check whether the device is LTE + NR dual connected */
     private boolean isUsingEnDc() {
         ServiceState ss = mTm.getServiceState();
-        return false;
-        // blocked by b/123096279
-        // return ss != null && ss.getNrStatus() == NR_STATUS_CONNECTED;
+        return ss != null && ss.getNrStatus() == NR_STATUS_CONNECTED;
     }
 
     /** Get the CellSignalStrength class type that should be returned when using a network type */
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 bb5857e..914660d 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -41,6 +41,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionPlan;
+import android.telephony.TelephonyManager;
 
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.internal.util.ArrayUtils;
@@ -167,7 +168,7 @@
     @Test
     public void testIsUsableSubscriptionId() throws Exception {
         if (!isSupported()) return;
-        assertTrue(SubscriptionManager.isUsableSubIdValue(mSubId));
+        assertTrue(SubscriptionManager.isUsableSubscriptionId(mSubId));
     }
 
     @Test
@@ -405,6 +406,15 @@
     }
 
     @Test
+    public void testSubscriptionInfoCarrierId() {
+        if (!isSupported()) return;
+
+        SubscriptionInfo info = mSm.getActiveSubscriptionInfo(mSubId);
+        int carrierId = info.getCarrierId();
+        assertTrue(carrierId >= TelephonyManager.UNKNOWN_CARRIER_ID);
+    }
+
+    @Test
     public void testSettingSubscriptionMeteredNess() throws Exception {
         if (!isSupported()) return;
 
diff --git a/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java b/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java
index 4732193..8058679 100644
--- a/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java
+++ b/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java
@@ -67,21 +67,6 @@
     }
 
     /**
-     * Tests the TelephonyManager.setLine1NumberForDisplay(long, string, string) API. This makes a
-     * call to setLine1NumberForDisplay() API and expects a SecurityException since the test apk is
-     * not signed by the certificate on the SIM.
-     */
-    public void testSetLine1NumberForDisplay2() {
-        try {
-            if (isSimCardPresent()) {
-                mTelephonyManager.setLine1NumberForDisplay(0, "", "");
-                fail("Expected SecurityException. App doesn't have carrier privileges.");
-            }
-        } catch (SecurityException expected) {
-        }
-    }
-
-    /**
      * Tests the TelephonyManager.iccOpenLogicalChannel() API. This makes a call to
      * iccOpenLogicalChannel() API and expects a SecurityException since the test apk is not signed
      * by certificate on the SIM.
@@ -172,34 +157,6 @@
     }
 
     /**
-     * Tests the TelephonyManager.nvWriteItem() API. This makes a call to nvWriteItem() API and
-     * expects a SecurityException since the test apk is not signed by a certificate on the SIM.
-     */
-    public void testNvWriteItem() {
-        try {
-            if (isSimCardPresent()) {
-                mTelephonyManager.nvWriteItem(0, "");
-                fail("Expected SecurityException. App doesn't have carrier privileges.");
-            }
-        } catch (SecurityException expected) {
-        }
-    }
-
-    /**
-     * Tests the TelephonyManager.nvWriteCdmaPrl() API. This makes a call to nvWriteCdmaPrl() API
-     * and expects a SecurityException since the test apk is not signed by a certificate on the SIM.
-     */
-    public void testNvWriteCdmaPrl() {
-        try {
-            if (isSimCardPresent()) {
-                mTelephonyManager.nvWriteCdmaPrl(null);
-                fail("Expected SecurityException. App doesn't have carrier privileges.");
-            }
-        } catch (SecurityException expected) {
-        }
-    }
-
-    /**
      * Tests the TelephonyManager.nvResetConfig() API. This makes a call to nvResetConfig() API and
      * expects a SecurityException since the test apk is not signed by a certificate on the SIM.
      */
diff --git a/tests/tests/theme/Android.bp b/tests/tests/theme/Android.bp
new file mode 100644
index 0000000..607f63f
--- /dev/null
+++ b/tests/tests/theme/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2012 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: "CtsThemeDeviceTestCases",
+    defaults: ["cts_defaults"],
+
+    static_libs: ["ctstestrunner"],
+
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+
+    srcs: ["src/**/*.java"],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+
+    sdk_version: "current",
+}
diff --git a/tests/tests/transition/Android.bp b/tests/tests/transition/Android.bp
new file mode 100644
index 0000000..317ec79
--- /dev/null
+++ b/tests/tests/transition/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+
+android_test {
+    name: "CtsTransitionTestCases",
+    defaults: ["cts_defaults"],
+
+    static_libs: [
+        "android-support-test",
+        "mockito-target-minus-junit4",
+        "hamcrest-library",
+        "android-common",
+        "compatibility-device-util",
+        "ctstestrunner",
+        "platform-test-annotations",
+    ],
+
+    libs: ["android.test.runner.stubs"],
+
+    srcs: ["src/**/*.java"],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+
+    sdk_version: "test_current",
+}
diff --git a/tests/tests/transition/Android.mk b/tests/tests/transition/Android.mk
deleted file mode 100644
index 5b721e0..0000000
--- a/tests/tests/transition/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsTransitionTestCases
-
-# 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 += \
-    android-support-test \
-    mockito-target-minus-junit4 \
-    hamcrest-library \
-    android-common \
-    compatibility-device-util \
-    ctstestrunner \
-    platform-test-annotations
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-# Enforce public / test api only
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/transition/AndroidTest.xml b/tests/tests/transition/AndroidTest.xml
index e75e8de..cac2338 100644
--- a/tests/tests/transition/AndroidTest.xml
+++ b/tests/tests/transition/AndroidTest.xml
@@ -16,6 +16,9 @@
 <configuration description="Config for CTS Transition test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
+    <!-- There is no difference between instant apps and installed apps with
+         respect to transition tests, so don't run these in instant apps. -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsTransitionTestCases.apk" />
diff --git a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
index c1248a5..70da07f 100644
--- a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
@@ -51,7 +51,7 @@
 
     private void resetTransition() {
         mExplode = new Explode();
-        mExplode.setDuration(500);
+        mExplode.setDuration(1000);
         mTransition = mExplode;
         resetListener();
     }
diff --git a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
index 63db5ef..dc4be47 100644
--- a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
@@ -72,7 +72,7 @@
         for (int i = 0; i < sSlideEdgeArray.length; i++) {
             final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
             final Slide slide = new Slide(slideEdge);
-            slide.setDuration(500);
+            slide.setDuration(1000);
             final Transition.TransitionListener listener =
                     mock(Transition.TransitionListener.class);
             slide.addListener(listener);
@@ -107,7 +107,7 @@
                         });
             });
             verify(listener, within(1000)).onTransitionStart(any());
-            verify(listener, within(1000)).onTransitionEnd(any());
+            verify(listener, within(2000)).onTransitionEnd(any());
 
             verifyMovement(redPoints, slideEdge, false);
             verifyMovement(greenPoints, slideEdge, false);
@@ -128,7 +128,7 @@
         for (int i = 0; i < sSlideEdgeArray.length; i++) {
             final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
             final Slide slide = new Slide(slideEdge);
-            slide.setDuration(500);
+            slide.setDuration(1000);
             final Transition.TransitionListener listener =
                     mock(Transition.TransitionListener.class);
             slide.addListener(listener);
@@ -172,7 +172,7 @@
                         });
             });
             verify(listener, within(1000)).onTransitionStart(any());
-            verify(listener, within(1000)).onTransitionEnd(any());
+            verify(listener, within(2000)).onTransitionEnd(any());
 
             verifyMovement(redPoints, slideEdge, true);
             verifyMovement(greenPoints, slideEdge, true);
diff --git a/tests/tests/uirendering/AndroidManifest.xml b/tests/tests/uirendering/AndroidManifest.xml
index cbbcfb3..d7adaf7 100644
--- a/tests/tests/uirendering/AndroidManifest.xml
+++ b/tests/tests/uirendering/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.uirendering.cts">
+          package="android.uirendering.cts"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/tests/tests/uirendering/AndroidTest.xml b/tests/tests/uirendering/AndroidTest.xml
index 369eb41..4661bbd 100644
--- a/tests/tests/uirendering/AndroidTest.xml
+++ b/tests/tests/uirendering/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS UI Rendering test cases">
     <option name="test-suite-tag" value="cts" />
     <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" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsUiRenderingTestCases.apk" />
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
index 57462b6..955d51f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
@@ -19,6 +19,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyFloat;
 import static org.mockito.Mockito.mock;
@@ -26,6 +27,7 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -137,6 +139,17 @@
     }
 
     @Test
+    public void testSetBlendMode() {
+        assertEdgeEffect(edgeEffect -> {
+            edgeEffect.setBlendMode(null);
+            assertNull(edgeEffect.getBlendMode());
+            edgeEffect.setBlendMode(EdgeEffect.DEFAULT_BLEND_MODE);
+            assertEquals(BlendMode.SRC_ATOP, edgeEffect.getBlendMode());
+            edgeEffect.onPull(1);
+        });
+    }
+
+    @Test
     public void testOnPullWithDisplacement() {
         assertEdgeEffect(edgeEffect -> {
             edgeEffect.onPull(1, 0);
diff --git a/tests/tests/util/AndroidTest.xml b/tests/tests/util/AndroidTest.xml
index 92c1e14..7f11f18 100644
--- a/tests/tests/util/AndroidTest.xml
+++ b/tests/tests/util/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS Util test cases">
     <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="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsUtilTestCases.apk" />
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index dabbc1a..2c03228 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -31,6 +31,15 @@
                 android:supportsRtl="true">
         <uses-library android:name="android.test.runner" />
 
+        <activity android:name="android.app.Activity"
+                  android:label="Empty Activity"
+                  android:theme="@style/ViewAttributeTestTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.view.cts.ViewStubCtsActivity"
                   android:screenOrientation="locked"
                   android:label="ViewStubCtsActivity">
diff --git a/tests/tests/view/jni/Android.bp b/tests/tests/view/jni/Android.bp
new file mode 100644
index 0000000..61932fc
--- /dev/null
+++ b/tests/tests/view/jni/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+
+cc_test_library {
+
+    name: "libctsview_jni",
+
+    cflags: ["-Werror"],
+
+    gtest: false,
+
+    srcs: [
+        "CtsViewJniOnLoad.cpp",
+        "android_view_cts_ASurfaceControlTest.cpp",
+        "android_view_cts_ChoreographerNativeTest.cpp",
+    ],
+
+    shared_libs: [
+        "libandroid",
+        "libnativehelper_compat_libc++",
+        "liblog",
+        "libsync",
+    ],
+
+    stl: "c++_static",
+
+    sdk_version: "current",
+
+}
diff --git a/tests/tests/view/jni/Android.mk b/tests/tests/view/jni/Android.mk
deleted file mode 100644
index 85c073b..0000000
--- a/tests/tests/view/jni/Android.mk
+++ /dev/null
@@ -1,38 +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_MODULE := libctsview_jni
-
-LOCAL_CFLAGS += -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-		CtsViewJniOnLoad.cpp \
-		android_view_cts_ASurfaceControlTest.cpp \
-		android_view_cts_ChoreographerNativeTest.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog libsync
-
-LOCAL_NDK_STL_VARIANT := c++_static
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp b/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
index dd6a186..2bfab1e 100644
--- a/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
+++ b/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
@@ -24,6 +24,7 @@
 #include <cinttypes>
 #include <string>
 
+#include <android/data_space.h>
 #include <android/hardware_buffer.h>
 #include <android/log.h>
 #include <android/native_window_jni.h>
@@ -212,6 +213,10 @@
             reinterpret_cast<ASurfaceTransaction*>(surfaceTransaction),
             reinterpret_cast<ASurfaceControl*>(surfaceControl), buffer, fence);
 
+    ASurfaceTransaction_setBufferDataSpace(
+            reinterpret_cast<ASurfaceTransaction*>(surfaceTransaction),
+            reinterpret_cast<ASurfaceControl*>(surfaceControl), ADATASPACE_UNKNOWN);
+
     return reinterpret_cast<jlong>(buffer);
 }
 
@@ -233,6 +238,10 @@
             reinterpret_cast<ASurfaceTransaction*>(surfaceTransaction),
             reinterpret_cast<ASurfaceControl*>(surfaceControl), buffer, fence);
 
+    ASurfaceTransaction_setBufferDataSpace(
+            reinterpret_cast<ASurfaceTransaction*>(surfaceTransaction),
+            reinterpret_cast<ASurfaceControl*>(surfaceControl), ADATASPACE_UNKNOWN);
+
     return reinterpret_cast<jlong>(buffer);
 }
 
diff --git a/tests/tests/view/res/layout/view_attribute_layout.xml b/tests/tests/view/res/layout/view_attribute_layout.xml
new file mode 100644
index 0000000..dd488ef
--- /dev/null
+++ b/tests/tests/view/res/layout/view_attribute_layout.xml
@@ -0,0 +1,50 @@
+<?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
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <View android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:id="@+id/view1"
+          android:paddingTop="7dp"
+          style="@style/ExplicitStyle1" />
+
+    <View android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:id="@+id/view2"
+          style="@style/ExplicitStyle2" />
+
+    <View android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:id="@+id/view3" />
+
+    <View android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:id="@+id/view4"
+          style="?android:attr/textAppearanceLarge"/>
+
+    <Button android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/button1" />
+
+    <Button android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/button2"
+            style="@style/ExplicitStyle1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/view/res/values/styles.xml b/tests/tests/view/res/values/styles.xml
index 5e47363..5b832c6 100644
--- a/tests/tests/view/res/values/styles.xml
+++ b/tests/tests/view/res/values/styles.xml
@@ -187,4 +187,26 @@
         <item name="android:windowContentTransitions">false</item>
         <item name="android:windowAnimationStyle">@null</item>
     </style>
+
+    <style name="ViewAttributeTestTheme" parent="@android:Theme.Material">
+        <item name="android:buttonStyle">@style/MyButtonStyle</item>
+    </style>
+
+    <style name="MyButtonStyle" parent="@style/MyButtonStyleParent">
+        <item name="android:paddingTop">3dp</item>
+    </style>
+
+    <style name="MyButtonStyleParent">
+        <item name="android:textColor">#ff00ff</item>
+    </style>
+
+    <style name="ExplicitStyle1" parent="@style/ParentOfExplicitStyle1">
+        <item name="android:padding">1dp</item>
+    </style>
+
+    <style name="ParentOfExplicitStyle1">
+        <item name="android:paddingLeft">2dp</item>
+    </style>
+
+    <style name="ExplicitStyle2" />
 </resources>
diff --git a/tests/tests/view/sdk28/Android.bp b/tests/tests/view/sdk28/Android.bp
new file mode 100644
index 0000000..87c6914
--- /dev/null
+++ b/tests/tests/view/sdk28/Android.bp
@@ -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.
+
+android_test {
+    name: "CtsViewTestCasesSdk28",
+    defaults: ["cts_defaults"],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+
+    compile_multilib: "both",
+
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+
+    static_libs: [
+        "android-support-test",
+        "ctstestrunner",
+        "platform-test-annotations",
+    ],
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    sdk_version: "28",
+
+}
diff --git a/tests/tests/view/sdk28/Android.mk b/tests/tests/view/sdk28/Android.mk
deleted file mode 100644
index 7d4f806..0000000
--- a/tests/tests/view/sdk28/Android.mk
+++ /dev/null
@@ -1,51 +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 := tests
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_MULTILIB := both
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
-    compatibility-device-util \
-    ctsdeviceutillegacy \
-    ctstestrunner \
-    mockito-target-minus-junit4 \
-    platform-test-annotations \
-    ub-uiautomator \
-    truth-prebuilt
-
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsview_jni libnativehelper_compat_libc++
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsViewTestCasesSdk28
-LOCAL_SDK_VERSION := 28
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/view/sdk28/AndroidTest.xml b/tests/tests/view/sdk28/AndroidTest.xml
index 1a64e98..004e8b5 100644
--- a/tests/tests/view/sdk28/AndroidTest.xml
+++ b/tests/tests/view/sdk28/AndroidTest.xml
@@ -20,10 +20,10 @@
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsViewTestCases.apk" />
+        <option name="test-file-name" value="CtsViewTestCasesSdk28.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.view.cts" />
+        <option name="package" value="android.view.cts.sdk28" />
         <option name="runtime-hint" value="6m47s" />
         <option name="hidden-api-checks" value="false" />
     </test>
diff --git a/tests/tests/view/sdk28/TEST_MAPPING b/tests/tests/view/sdk28/TEST_MAPPING
new file mode 100644
index 0000000..d2d36ce
--- /dev/null
+++ b/tests/tests/view/sdk28/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsViewTestCasesSdk28"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
index fb9e27d..5fe1141 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
@@ -599,90 +599,6 @@
     }
 
     @Test
-    public void testAddRemoveAnimationListener() throws Throwable {
-        final View animWindow = mActivity.findViewById(R.id.anim_window);
-
-        // XML file of R.anim.accelerate_alpha
-        // <alpha xmlns:android="http://schemas.android.com/apk/res/android"
-        //      android:interpolator="@android:anim/accelerate_interpolator"
-        //      android:fromAlpha="0.1"
-        //      android:toAlpha="0.9"
-        //      android:duration="1000" />
-        final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha);
-        // Speed things up a little
-        anim.setDuration(10);
-
-        final AnimationListener l1 = mock(AnimationListener.class);
-        final AnimationListener l2 = mock(AnimationListener.class);
-        final AnimationListener l3 = mock(AnimationListener.class);
-        final AnimationListener l4 = mock(AnimationListener.class);
-
-        // Test that adding listeners does not remove the set listener
-        anim.setAnimationListener(l1);
-        anim.addAnimationListener(l2);
-        anim.addAnimationListener(l3);
-        verifyZeroInteractions(l1, l2, l3, l4);
-
-        // set: l1
-        // added: l2, l3
-        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
-        verifyListeners(anim, l1, l2, l3);
-        verifyZeroInteractions(l4);
-
-        // Test that setting a listener does not remove the added listeners
-        reset(l1, l2, l3, l4);
-        anim.setAnimationListener(l4);
-        verifyZeroInteractions(l1, l2, l3, l4);
-
-        // set: l4
-        // added: l2, l3
-        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
-        verifyListeners(anim, l2, l3, l4);
-        verifyZeroInteractions(l1);
-
-        // Test that removing a listener does not affect the set listener
-        reset(l1, l2, l3, l4);
-        anim.removeAnimationListener(l2);
-        verifyZeroInteractions(l1, l2, l3, l4);
-
-        // set: l4
-        // added: l3
-        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
-        verifyListeners(anim, l3, l4);
-        verifyZeroInteractions(l1, l2);
-
-        // Test that removing the set listener does not affect the set listener
-        reset(l1, l2, l3, l4);
-        anim.removeAnimationListener(l4);
-        verifyZeroInteractions(l1, l2, l3, l4);
-
-        // set: l4
-        // added: l3
-        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
-        verifyListeners(anim, l3, l4);
-        verifyZeroInteractions(l1, l2);
-
-        // Test that setting the set listener to null does not remove the added listeners
-        reset(l1, l2, l3, l4);
-        anim.setAnimationListener(null);
-        verifyZeroInteractions(l1, l2, l3, l4);
-
-        // set: null
-        // added: l3
-        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
-        verifyListeners(anim, l3);
-        verifyZeroInteractions(l1, l2, l4);
-    }
-
-    private void verifyListeners(Animation anim, AnimationListener... listeners) {
-        for (AnimationListener listener : listeners) {
-            verify(listener, times(1)).onAnimationStart(anim);
-            verify(listener, times(1)).onAnimationEnd(anim);
-            verify(listener, never()).onAnimationRepeat(anim);
-        }
-    }
-
-    @Test
     public void testStart() {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha);
         animation.setStartTime(0);
diff --git a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
index 3460525..7d6228d 100644
--- a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -26,6 +27,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -53,6 +55,9 @@
 import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class LayoutInflaterTest {
@@ -412,6 +417,39 @@
         assertNotNull(container.findViewById(R.id.include_layout_from_attr));
     }
 
+    // API : LayoutInflater#onCreateView(Context, View, String, AttributeSet)
+    // API : LayoutInflater#createView(Context, String, prefix, AttributeSet)
+    // onCreateView with Context should be called when there is no factory to inflate and should
+    // pass the LayoutInflater's context at the root and the parent's context other times.
+    // createView with Context should be called when there is a "." in the name.
+    @Test
+    public void testCreateViewWithContext() throws Throwable {
+        final Context context = mLayoutInflater.getContext();
+        CreateViewContextInflater inflater = new CreateViewContextInflater(context);
+        final ViewGroup container = (ViewGroup) inflater.inflate(R.layout.inflater_layout, null);
+
+        // The LinearLayout and TextViews inflate with onCreateView
+        assertEquals(9, inflater.onCreateViewCalls.size());
+        assertEquals(context, inflater.onCreateViewCalls.get(0)[0]);
+        assertNull(inflater.onCreateViewCalls.get(0)[1]);
+        assertEquals("LinearLayout", inflater.onCreateViewCalls.get(0)[2]);
+
+        Context parentContext = container.getContext();
+        // This should be a wrapper context since MethodTrackerInflater changes LinearLayout context
+        assertNotSame(context, parentContext);
+        for (int i = 1; i < 9; i++) {
+            Object[] params = inflater.onCreateViewCalls.get(i);
+            assertEquals(parentContext, params[0]);
+            assertEquals(container, params[1]);
+            assertEquals("TextView", params[2]);
+        }
+
+        // Also has android.view.ct.MockViewStub
+        assertEquals(9, container.getChildCount());
+        View mockViewStub = container.getChildAt(8);
+        assertEquals(parentContext, mockViewStub.getContext());
+    }
+
     static class MockLayoutInflater extends LayoutInflater {
 
         public MockLayoutInflater(Context c) {
@@ -434,6 +472,41 @@
         }
     }
 
+    /**
+     * Used to track calling of onCreateView protected method.
+     */
+    static class CreateViewContextInflater extends LayoutInflater {
+        public final List<Object[]> onCreateViewCalls = new ArrayList<>();
+
+        CreateViewContextInflater(Context context) {
+            super(context);
+        }
+
+        @Override
+        public LayoutInflater cloneInContext(Context newContext) {
+            return null;
+        }
+
+        @Override
+        public View onCreateView(Context viewContext, View parent, String name,
+                AttributeSet attrs) throws ClassNotFoundException {
+            onCreateViewCalls.add(new Object[] {viewContext, parent, name, attrs});
+            if ("LinearLayout".equals(name)) {
+                viewContext = new ContextWrapper(viewContext);
+            }
+            String prefix = null;
+            int dotIndex = name.lastIndexOf('.');
+            if (dotIndex >= 0) {
+                prefix = name.substring(0, dotIndex + 1);
+                name = name.substring(dotIndex + 1);
+            } else {
+                prefix = "android.widget.";
+            }
+
+            return createView(viewContext, name, prefix, attrs);
+        }
+    }
+
     private XmlResourceParser getParser() {
         XmlResourceParser parser = null;
         ActivityInfo ai = null;
diff --git a/tests/tests/view/src/android/view/cts/ViewAttributeTest.java b/tests/tests/view/src/android/view/cts/ViewAttributeTest.java
new file mode 100644
index 0000000..02766d9
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/ViewAttributeTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.view.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Map;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewAttributeTest {
+
+    @Rule
+    public ActivityTestRule<Activity> mActivityRule =
+            new ActivityTestRule<>(Activity.class, true, false);
+
+    private static final String DISABLE_SHELL_COMMAND =
+            "settings delete global debug_view_attributes_application_package";
+
+    private static final String ENABLE_SHELL_COMMAND =
+            "settings put global debug_view_attributes_application_package android.view.cts";
+
+    private UiDevice mUiDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mUiDevice.executeShellCommand(ENABLE_SHELL_COMMAND);
+        mActivityRule.launchActivity(null);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mUiDevice.executeShellCommand(DISABLE_SHELL_COMMAND);
+    }
+
+    @Test
+    public void testGetExplicitStyle() {
+        Context context = InstrumentationRegistry.getTargetContext();
+        LayoutInflater inflater = LayoutInflater.from(context);
+        LinearLayout rootView =
+                (LinearLayout) inflater.inflate(R.layout.view_attribute_layout, null);
+        View view1 = rootView.findViewById(R.id.view1);
+        assertEquals(R.style.ExplicitStyle1, view1.getExplicitStyle());
+
+        View view2 = rootView.findViewById(R.id.view2);
+        assertEquals(R.style.ExplicitStyle2, view2.getExplicitStyle());
+
+        View view3 = rootView.findViewById(R.id.view3);
+        assertEquals(Resources.ID_NULL, view3.getExplicitStyle());
+
+        View view4 = rootView.findViewById(R.id.view4);
+        assertEquals(android.R.style.TextAppearance_Material_Large, view4.getExplicitStyle());
+    }
+
+    @Test
+    public void testGetAttributeResolutionStack() {
+        LayoutInflater inflater = LayoutInflater.from(mActivityRule.getActivity());
+        LinearLayout rootView =
+                (LinearLayout) inflater.inflate(R.layout.view_attribute_layout, null);
+        List<Integer> stackRootView = rootView.getAttributeResolutionStack();
+        assertEquals(1, stackRootView.size());
+        assertEquals(R.layout.view_attribute_layout, stackRootView.get(0).intValue());
+
+        // View that has an explicit style ExplicitStyle1 set via style = ...
+        View view1 = rootView.findViewById(R.id.view1);
+        List<Integer> stackView1 = view1.getAttributeResolutionStack();
+        assertEquals(3, stackView1.size());
+        assertEquals(R.layout.view_attribute_layout, stackView1.get(0).intValue());
+        assertEquals(R.style.ExplicitStyle1, stackView1.get(1).intValue());
+        assertEquals(R.style.ParentOfExplicitStyle1, stackView1.get(2).intValue());
+
+        // Button that has the default style MyButtonStyle set in ViewStyleTestTheme Activity theme
+        // via android:buttonStyle
+        Button button1 = rootView.findViewById(R.id.button1);
+        List<Integer> stackButton1 = button1.getAttributeResolutionStack();
+        assertEquals(3, stackButton1.size());
+        assertEquals(R.layout.view_attribute_layout, stackButton1.get(0).intValue());
+        assertEquals(R.style.MyButtonStyle, stackButton1.get(1).intValue());
+        assertEquals(R.style.MyButtonStyleParent, stackButton1.get(2).intValue());
+
+        // Button that has the default style MyButtonStyle set in ViewStyleTestTheme Activity theme
+        // via android:buttonStyle and has an explicit style ExplicitStyle1 set via style = ...
+        Button button2 = rootView.findViewById(R.id.button2);
+        List<Integer> stackButton2 = button2.getAttributeResolutionStack();
+        assertEquals(5, stackButton2.size());
+        assertEquals(R.layout.view_attribute_layout, stackButton2.get(0).intValue());
+        assertEquals(R.style.ExplicitStyle1, stackButton2.get(1).intValue());
+        assertEquals(R.style.ParentOfExplicitStyle1, stackButton2.get(2).intValue());
+        assertEquals(R.style.MyButtonStyle, stackButton2.get(3).intValue());
+        assertEquals(R.style.MyButtonStyleParent, stackButton2.get(4).intValue());
+    }
+
+    @Test
+    public void testGetAttributeSourceResourceMap() {
+        LayoutInflater inflater = LayoutInflater.from(mActivityRule.getActivity());
+        LinearLayout rootView =
+                (LinearLayout) inflater.inflate(R.layout.view_attribute_layout, null);
+        Map<Integer, Integer> attributeMapRootView = rootView.getAttributeSourceResourceMap();
+        assertEquals(R.layout.view_attribute_layout,
+                (attributeMapRootView.get(android.R.attr.orientation)).intValue());
+
+        // View that has an explicit style ExplicitStyle1 set via style = ...
+        View view1 = rootView.findViewById(R.id.view1);
+        Map<Integer, Integer> attributeMapView1 = view1.getAttributeSourceResourceMap();
+        assertEquals(R.style.ExplicitStyle1,
+                (attributeMapView1.get(android.R.attr.padding)).intValue());
+        assertEquals(R.style.ParentOfExplicitStyle1,
+                (attributeMapView1.get(android.R.attr.paddingLeft)).intValue());
+        assertEquals(R.layout.view_attribute_layout,
+                (attributeMapView1.get(android.R.attr.paddingTop)).intValue());
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
index aa9dcf1..d8c293f 100644
--- a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
@@ -19,9 +19,11 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.TypedValue;
 import android.view.ViewConfiguration;
 
 import org.junit.Test;
@@ -65,7 +67,8 @@
 
     @Test
     public void testInstanceValues() {
-        ViewConfiguration vc = ViewConfiguration.get(InstrumentationRegistry.getTargetContext());
+        Context context = InstrumentationRegistry.getTargetContext();
+        ViewConfiguration vc = ViewConfiguration.get(context);
         assertNotNull(vc);
 
         vc.getScaledDoubleTapSlop();
@@ -83,6 +86,30 @@
         vc.getScaledTouchSlop();
         vc.getScaledWindowTouchSlop();
         vc.hasPermanentMenuKey();
+
+        float pixelsToMmRatio = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
+                context.getResources().getDisplayMetrics());
+
+        // Verify that the min scaling span size is reasonable.
+        float scaledMinScalingSpanMm = vc.getScaledMinScalingSpan() / pixelsToMmRatio;
+        assertTrue(scaledMinScalingSpanMm > 0);
+        assertTrue(scaledMinScalingSpanMm < 40.5); // 1.5 times the recommended size of 27mm
+    }
+
+    @Test
+    public void testExceptionsThrown() {
+        ViewConfiguration vc = new ViewConfiguration();
+        boolean correctExceptionThrown = false;
+        try {
+            vc.getScaledMinScalingSpan();
+        } catch (IllegalStateException e) {
+            if (e.getMessage().equals("Min scaling span cannot be determined when this "
+                    + "method is called on a ViewConfiguration that was instantiated using a "
+                    + "constructor with no Context parameter")) {
+                correctExceptionThrown = true;
+            }
+        }
+        assertTrue(correctExceptionThrown);
     }
 
     /**
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java b/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
index 8e34571..484644f 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
@@ -313,7 +313,7 @@
         assertThat(request.getConversation().get(0).getText().toString()).isEqualTo(TEXT);
         assertThat(request.getConversation().get(0).getAuthor()).isEqualTo(PERSON);
         assertThat(request.getHints()).isEmpty();
-        assertThat(request.getMaxSuggestions()).isEqualTo(0);
+        assertThat(request.getMaxSuggestions()).isEqualTo(-1);
         assertThat(request.getTypeConfig()).isNotNull();
         assertThat(request.getConversationId()).isNull();
     }
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index 5b97823..7bdb094 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS Voice Settings test cases">
     <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="not_multi_abi" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
@@ -27,7 +29,9 @@
 
         <!-- Close the "turn on battery saver?" dialog, and wait for the broadcast queue to drain. -->
         <option name="teardown-command" value="am broadcast --receiver-foreground -a android.intent.action.CLOSE_SYSTEM_DIALOGS" />
+        <!-- TODO(b/123958025): disabled because it hangs most of the time
         <option name="teardown-command" value="am wait-for-broadcast-idle" />
+        -->
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.voicesettings.cts" />
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index db6bbb9..2ef1999 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -40,6 +40,7 @@
         super.setUp();
         mContext = getInstrumentation().getTargetContext();
         mHasFeature = mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS);
+        Log.v(TAG, "setUp(): mHasFeature=" + mHasFeature);
     }
 
     public AirplaneModeTest() {
@@ -84,6 +85,7 @@
             }
             runTest(BroadcastUtils.TestcaseType.AIRPLANE_MODE_ON, AIRPLANE_MODE_IS_ON);
         }
+        Log.i(TAG, "All done!");
     }
 
     private boolean runTest(BroadcastUtils.TestcaseType test, int expectedMode) throws Exception {
diff --git a/tests/tests/webkit/AndroidTest.xml b/tests/tests/webkit/AndroidTest.xml
index 903aef7..a25f80b 100644
--- a/tests/tests/webkit/AndroidTest.xml
+++ b/tests/tests/webkit/AndroidTest.xml
@@ -16,6 +16,10 @@
 <configuration description="Config for CTS Webkit test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="webview" />
+    <!-- Note: about half of webkit CTS tests are skipped in instant_app mode since it requires HTTPS -->
+    <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.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/webkit/src/android/webkit/cts/ChromeClient.java b/tests/tests/webkit/src/android/webkit/cts/ChromeClient.java
index 5435cf8..a78f219 100644
--- a/tests/tests/webkit/src/android/webkit/cts/ChromeClient.java
+++ b/tests/tests/webkit/src/android/webkit/cts/ChromeClient.java
@@ -18,33 +18,25 @@
 import android.webkit.ConsoleMessage;
 import android.webkit.cts.WebViewSyncLoader.WaitForProgressClient;
 
+import com.google.common.util.concurrent.SettableFuture;
+
 // A chrome client for listening webview chrome events.
 class ChromeClient extends WaitForProgressClient {
-
-    private boolean mIsMessageLevelAvailable;
-    private ConsoleMessage.MessageLevel mMessageLevel;
+    private final SettableFuture<ConsoleMessage.MessageLevel> mMessageLevel =
+            SettableFuture.create();
 
     public ChromeClient(WebViewOnUiThread onUiThread) {
         super(onUiThread);
     }
 
     @Override
-    public synchronized boolean onConsoleMessage(ConsoleMessage message) {
-        mMessageLevel = message.messageLevel();
-        mIsMessageLevelAvailable = true;
-        notify();
+    public boolean onConsoleMessage(ConsoleMessage message) {
+        mMessageLevel.set(message.messageLevel());
         // return false for default handling; i.e. printing the message.
         return false;
     }
 
-    public synchronized ConsoleMessage.MessageLevel getMessageLevel(int timeout) {
-        for(; timeout > 0; timeout -= 1000) {
-            if( mIsMessageLevelAvailable ) break;
-            try {
-                wait(1000);
-            } catch (InterruptedException e) {
-            }
-        }
-        return mMessageLevel;
+    public ConsoleMessage.MessageLevel getMessageLevel() {
+        return WebkitUtils.waitForFuture(mMessageLevel);
     }
 }
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
index 843e81e..08bbc67 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
@@ -16,6 +16,7 @@
 
 package android.webkit.cts;
 
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
@@ -33,6 +34,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+@AppModeFull
 public class CookieManagerTest extends
         ActivityInstrumentationTestCase2<CookieSyncManagerCtsActivity> {
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
index f4724cf..2b12f19 100644
--- a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
@@ -16,6 +16,7 @@
 
 package android.webkit.cts;
 
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.HttpAuthHandler;
 import android.webkit.WebView;
@@ -25,6 +26,7 @@
 
 import org.apache.http.HttpStatus;
 
+@AppModeFull
 public class HttpAuthHandlerTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
 
     private static final long TIMEOUT = 10000;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index c881de4..e59daf5 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.os.Message;
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.MotionEvent;
 import android.view.ViewGroup;
@@ -32,6 +33,7 @@
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
 
+@AppModeFull
 public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private static final long TEST_TIMEOUT = 5000L;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
index d2c54f0..cae5ff8 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
@@ -17,6 +17,7 @@
 package android.webkit.cts;
 
 import android.graphics.Bitmap;
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.WebBackForwardList;
 import android.webkit.cts.WebViewSyncLoader.WaitForProgressClient;
@@ -27,6 +28,7 @@
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
 
+@AppModeFull
 public class WebHistoryItemTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private final static long TEST_TIMEOUT = 10000;
     private CtsTestServer mWebServer;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index eac21a9..b9b50d4 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -20,6 +20,7 @@
 import android.net.http.SslError;
 import android.os.Build;
 import android.os.Message;
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Base64;
 import android.util.Log;
@@ -49,9 +50,13 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
 /**
  * Tests for {@link android.webkit.WebSettings}
  */
+@AppModeFull
 public class WebSettingsTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
 
     private static final int WEBVIEW_TIMEOUT = 5000;
@@ -214,10 +219,14 @@
         assertEquals(TestHtmlConstants.WEBPAGE_NOT_AVAILABLE_TITLE, mOnUiThread.getTitle());
     }
 
-    public void testAccessCacheMode() throws Throwable {
+    public void testAccessCacheMode_defaultValue() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
+        assertEquals(WebSettings.LOAD_DEFAULT, mSettings.getCacheMode());
+    }
+
+    private void openIconDatabase() throws InterruptedException {
         WebkitUtils.onMainThreadSync(() -> {
             // getInstance must run on the UI thread
             WebIconDatabase iconDb = WebIconDatabase.getInstance();
@@ -226,64 +235,81 @@
         });
         getInstrumentation().waitForIdleSync();
         Thread.sleep(100); // Wait for open to be received on the icon db thread.
-        assertEquals(WebSettings.LOAD_DEFAULT, mSettings.getCacheMode());
+    }
+
+    public void testAccessCacheMode_cacheElseNetwork() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        openIconDatabase();
+        final IconListenerClient iconListener = new IconListenerClient();
+        mOnUiThread.setWebChromeClient(iconListener);
+        startWebServer();
 
         mSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
         assertEquals(WebSettings.LOAD_CACHE_ELSE_NETWORK, mSettings.getCacheMode());
+        int initialRequestCount = mWebServer.getRequestCount();
+        loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        iconListener.waitForNextIcon();
+        int requestCountAfterFirstLoad = mWebServer.getRequestCount();
+        assertTrue("Must fetch non-cached resource from server",
+                requestCountAfterFirstLoad > initialRequestCount);
+        iconListener.drainIconQueue();
+        loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        iconListener.waitForNextIcon();
+        int requestCountAfterSecondLoad = mWebServer.getRequestCount();
+        assertEquals("Expected to use cache instead of re-fetching resource",
+                requestCountAfterSecondLoad, requestCountAfterFirstLoad);
+    }
+
+    public void testAccessCacheMode_noCache() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        openIconDatabase();
         final IconListenerClient iconListener = new IconListenerClient();
         mOnUiThread.setWebChromeClient(iconListener);
-        loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        new PollingCheck(WEBVIEW_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return iconListener.mReceivedIcon;
-            }
-        }.run();
-        int firstFetch = mWebServer.getRequestCount();
-        iconListener.mReceivedIcon = false;
-        loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        new PollingCheck(WEBVIEW_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return iconListener.mReceivedIcon;
-            }
-        }.run();
-        assertEquals(firstFetch, mWebServer.getRequestCount());
+        startWebServer();
 
         mSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
         assertEquals(WebSettings.LOAD_NO_CACHE, mSettings.getCacheMode());
-        iconListener.mReceivedIcon = false;
+        int initialRequestCount = mWebServer.getRequestCount();
         loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        new PollingCheck(WEBVIEW_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return iconListener.mReceivedIcon;
-            }
-        }.run();
-        int secondFetch = mWebServer.getRequestCount();
-        iconListener.mReceivedIcon = false;
+        iconListener.waitForNextIcon();
+        int requestCountAfterFirstLoad = mWebServer.getRequestCount();
+        assertTrue("Must fetch non-cached resource from server",
+                requestCountAfterFirstLoad > initialRequestCount);
+        iconListener.drainIconQueue();
         loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        new PollingCheck(WEBVIEW_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return iconListener.mReceivedIcon;
-            }
-        }.run();
-        int thirdFetch = mWebServer.getRequestCount();
-        assertTrue(firstFetch < secondFetch);
-        assertTrue(secondFetch < thirdFetch);
+        iconListener.waitForNextIcon();
+        int requestCountAfterSecondLoad = mWebServer.getRequestCount();
+        assertTrue("Expected to re-fetch resource instead of caching",
+                requestCountAfterSecondLoad > requestCountAfterFirstLoad);
+    }
+
+    public void testAccessCacheMode_cacheOnly() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        openIconDatabase();
+        final IconListenerClient iconListener = new IconListenerClient();
+        mOnUiThread.setWebChromeClient(iconListener);
+        startWebServer();
+
+        // As a precondition, get the icon in the cache.
+        mSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
+        loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        iconListener.waitForNextIcon();
 
         mSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
         assertEquals(WebSettings.LOAD_CACHE_ONLY, mSettings.getCacheMode());
-        iconListener.mReceivedIcon = false;
+        iconListener.drainIconQueue();
+        int initialRequestCount = mWebServer.getRequestCount();
         loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        new PollingCheck(WEBVIEW_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return iconListener.mReceivedIcon;
-            }
-        }.run();
-        assertEquals(thirdFetch, mWebServer.getRequestCount());
+        iconListener.waitForNextIcon();
+        int requestCountAfterFirstLoad = mWebServer.getRequestCount();
+        assertEquals("Expected to use cache instead of fetching resource",
+                requestCountAfterFirstLoad, initialRequestCount);
     }
 
     public void testAccessCursiveFontFamily() throws Exception {
@@ -754,29 +780,65 @@
         }
     }
 
-    public void testLoadsImagesAutomatically() throws Throwable {
+    public void testLoadsImagesAutomatically_default() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
         assertTrue(mSettings.getLoadsImagesAutomatically());
+    }
 
+    public void testLoadsImagesAutomatically_httpImagesLoaded() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         startWebServer();
         mSettings.setJavaScriptEnabled(true);
+        mSettings.setLoadsImagesAutomatically(true);
 
-        // Check that by default network and data url images are loaded.
         mOnUiThread.loadDataAndWaitForCompletion(getNetworkImageHtml(), "text/html", null);
         assertEquals(NETWORK_IMAGE_HEIGHT, mOnUiThread.getTitle());
+    }
+
+    public void testLoadsImagesAutomatically_dataUriImagesLoaded() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        startWebServer();
+        mSettings.setJavaScriptEnabled(true);
+        mSettings.setLoadsImagesAutomatically(true);
+
         mOnUiThread.loadDataAndWaitForCompletion(DATA_URL_IMAGE_HTML, "text/html", null);
         assertEquals(DATA_URL_IMAGE_HEIGHT, mOnUiThread.getTitle());
+    }
 
-        // Check that with auto-loading turned off no images are loaded.
-        // Also check that images are loaded automatically once we enable the setting,
-        // without reloading the page.
+    public void testLoadsImagesAutomatically_blockLoadingImages() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        startWebServer();
+        mSettings.setJavaScriptEnabled(true);
         mSettings.setLoadsImagesAutomatically(false);
-        mOnUiThread.clearCache(true);
+
+        mOnUiThread.clearCache(true); // in case of side-effects from other tests
         mOnUiThread.loadDataAndWaitForCompletion(getNetworkImageHtml(), "text/html", null);
         assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
-        mSettings.setLoadsImagesAutomatically(true);
+
+        mOnUiThread.loadDataAndWaitForCompletion(DATA_URL_IMAGE_HTML, "text/html", null);
+        assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
+    }
+
+    public void testLoadsImagesAutomatically_loadImagesWithoutReload() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        startWebServer();
+        mSettings.setJavaScriptEnabled(true);
+        mSettings.setLoadsImagesAutomatically(false);
+
+        mOnUiThread.clearCache(true); // in case of side-effects from other tests
+        mOnUiThread.loadDataAndWaitForCompletion(getNetworkImageHtml(), "text/html", null);
+        assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
+        mSettings.setLoadsImagesAutomatically(true); // load images, without calling #reload()
         waitForNonEmptyImage();
         assertEquals(NETWORK_IMAGE_HEIGHT, mOnUiThread.getTitle());
 
@@ -784,7 +846,7 @@
         mOnUiThread.clearCache(true);
         mOnUiThread.loadDataAndWaitForCompletion(DATA_URL_IMAGE_HTML, "text/html", null);
         assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
-        mSettings.setLoadsImagesAutomatically(true);
+        mSettings.setLoadsImagesAutomatically(true); // load images, without calling #reload()
         waitForNonEmptyImage();
         assertEquals(DATA_URL_IMAGE_HEIGHT, mOnUiThread.getTitle());
     }
@@ -913,7 +975,7 @@
         mOnUiThread.loadUrlAndWaitForCompletion(url);
         String iframeUrl = TestHtmlConstants.getFileUrl(TestHtmlConstants.HELLO_WORLD_URL);
         assertFalse(iframeUrl.equals(mOnUiThread.getTitle()));
-        assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel(10000));
+        assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel());
     }
 
     // Verify that enabling file access from file URLs enable XmlHttpRequest (XHR) across files
@@ -933,7 +995,7 @@
         final ChromeClient webChromeClient = new ChromeClient(mOnUiThread);
         mOnUiThread.setWebChromeClient(webChromeClient);
         verifyFileXHR(false);
-        assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel(10000));
+        assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel());
     }
 
     // verify XHR across files matches the allowFileAccessFromFileURLs setting
@@ -1115,7 +1177,7 @@
     }
 
     private class IconListenerClient extends WaitForProgressClient {
-        public boolean mReceivedIcon;
+        private final BlockingQueue<Bitmap> mReceivedIconQueue = new LinkedBlockingQueue<>();
 
         public IconListenerClient() {
             super(mOnUiThread);
@@ -1123,7 +1185,20 @@
 
         @Override
         public void onReceivedIcon(WebView view, Bitmap icon) {
-            mReceivedIcon = true;
+            mReceivedIconQueue.add(icon);
+        }
+
+        /**
+         * Exposed as a precaution, in case for some reason we get multiple calls to
+         * {@link #onReceivedIcon}.
+         */
+        public void drainIconQueue() {
+            while (mReceivedIconQueue.poll() != null) {}
+        }
+
+        public void waitForNextIcon() {
+            // TODO(ntfschr): consider exposing the Bitmap, if we want to make assertions.
+            WebkitUtils.waitForNextQueueElement(mReceivedIconQueue);
         }
     }
 }
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 8f08dc7..a0b0ef5 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -20,6 +20,7 @@
 import android.graphics.Bitmap;
 import android.os.Build;
 import android.os.Message;
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
 import android.view.ViewGroup;
@@ -48,6 +49,7 @@
 import java.util.List;
 import java.util.ArrayList;
 
+@AppModeFull
 public class WebViewClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private static final long TEST_TIMEOUT = 5000;
     private static final String TEST_URL = "http://www.example.com/";
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewRendererClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewRendererClientTest.java
index dfdbcee..a372638 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewRendererClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewRendererClientTest.java
@@ -16,6 +16,7 @@
 
 package android.webkit.cts;
 
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
 import android.webkit.JavascriptInterface;
@@ -30,6 +31,7 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicInteger;
 
+@AppModeFull
 public class WebViewRendererClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private WebViewOnUiThread mOnUiThread;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewRendererTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewRendererTest.java
index e209d87..a99427b 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewRendererTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewRendererTest.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SuppressLint;
 import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.RenderProcessGoneDetail;
 import android.webkit.WebView;
@@ -28,6 +29,7 @@
 
 import java.util.concurrent.Future;
 
+@AppModeFull
 public class WebViewRendererTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private WebViewOnUiThread mOnUiThread;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index bbaac70..6fbdb89 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -39,6 +39,7 @@
 import android.os.StrictMode;
 import android.os.StrictMode.ThreadPolicy;
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.Presubmit;
 import android.print.PageRange;
 import android.print.PrintAttributes;
@@ -118,12 +119,17 @@
 import org.apache.http.util.EncodingUtils;
 import org.apache.http.util.EntityUtils;
 
+@AppModeFull
 public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     public static final long TEST_TIMEOUT = 20000L;
     private static final int INITIAL_PROGRESS = 100;
     private static final String X_REQUESTED_WITH = "X-Requested-With";
     private static final String PRINTER_TEST_FILE = "print.pdf";
     private static final String PDF_PREAMBLE = "%PDF-1";
+    // Snippet of HTML that will prevent favicon requests to the test server.
+    private static final String HTML_HEADER =
+            "<html><head><link rel=\"shortcut icon\" href=\"%23\" /></head>";
+    private static final String SIMPLE_HTML = "<html><body>simple html</body></html>";
 
     /**
      * This is the minimum number of milliseconds to wait for scrolling to
@@ -147,11 +153,6 @@
      */
     private static final long SCROLL_WAIT_INTERVAL_MS = 200;
 
-    /**
-     * Epsilon used in page scale value comparisons.
-     */
-    private static final float PAGE_SCALE_EPSILON = 0.0001f;
-
     private WebView mWebView;
     private CtsTestServer mWebServer;
     private WebViewOnUiThread mOnUiThread;
@@ -296,122 +297,6 @@
         assertNull(WebView.findAddress("This is not an address: no town, no state, no zip."));
     }
 
-    @SuppressWarnings("deprecation")
-    @UiThreadTest
-    public void testGetZoomControls() {
-        if (!NullWebViewUtils.isWebViewAvailable()) {
-            return;
-        }
-        WebSettings settings = mWebView.getSettings();
-        assertTrue(settings.supportZoom());
-        View zoomControls = mWebView.getZoomControls();
-        assertNotNull(zoomControls);
-
-        // disable zoom support
-        settings.setSupportZoom(false);
-        assertFalse(settings.supportZoom());
-        assertNull(mWebView.getZoomControls());
-    }
-
-    @UiThreadTest
-    public void testInvokeZoomPicker() throws Exception {
-        if (!NullWebViewUtils.isWebViewAvailable()) {
-            return;
-        }
-        WebSettings settings = mWebView.getSettings();
-        assertTrue(settings.supportZoom());
-        startWebServer(false);
-        String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mOnUiThread.loadUrlAndWaitForCompletion(url);
-        mWebView.invokeZoomPicker();
-    }
-
-    public void testZoom() throws Throwable {
-        if (!NullWebViewUtils.isWebViewAvailable()) {
-            return;
-        }
-
-        // Pinch zoom is not supported in wrap_content layouts.
-        mOnUiThread.setLayoutHeightToMatchParent();
-
-        final ScaleChangedWebViewClient webViewClient = new ScaleChangedWebViewClient();
-        mOnUiThread.setWebViewClient(webViewClient);
-
-        mWebServer = new CtsTestServer(getActivity());
-        mOnUiThread.loadUrlAndWaitForCompletion(
-                mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
-        pollingCheckForCanZoomIn();
-
-        WebSettings settings = mOnUiThread.getSettings();
-        settings.setSupportZoom(false);
-        assertFalse(settings.supportZoom());
-        float currScale = mOnUiThread.getScale();
-        float previousScale = currScale;
-
-        // can zoom in or out although zoom support is disabled in web settings
-        assertTrue(mOnUiThread.zoomIn());
-        currScale = webViewClient.expectZoomIn(currScale);
-
-        assertTrue(mOnUiThread.zoomOut());
-        currScale = webViewClient.expectZoomOut(currScale);
-
-        mOnUiThread.zoomBy(1.25f); // zoom in
-        currScale = webViewClient.expectZoomBy(currScale, 1.25f);
-
-        mOnUiThread.zoomBy(0.8f); // zoom out
-        currScale = webViewClient.expectZoomBy(currScale, 0.8f);
-
-        // enable zoom support
-        settings.setSupportZoom(true);
-        assertTrue(settings.supportZoom());
-
-        // Zoom in until maximum scale, in default increments.
-        while (mOnUiThread.zoomIn()) {
-            currScale = webViewClient.expectZoomIn(currScale);
-        }
-
-        assertFalse(mOnUiThread.zoomIn());
-        assertNoScaleChange(webViewClient, currScale);
-
-        // Zoom out until minimum scale, in default increments.
-        while (mOnUiThread.zoomOut()) {
-            currScale = webViewClient.expectZoomOut(currScale);
-        }
-
-        assertFalse(mOnUiThread.zoomOut());
-        assertNoScaleChange(webViewClient, currScale);
-
-        // Zoom in until maximum scale, in specified increments designed so that the last zoom will
-        // be less than expected.
-        while (mOnUiThread.canZoomIn()) {
-            mOnUiThread.zoomBy(1.7f);
-            currScale = webViewClient.expectZoomBy(currScale, 1.7f);
-        }
-
-        // At this point, zooming in should do nothing.
-        mOnUiThread.zoomBy(1.7f);
-        assertNoScaleChange(webViewClient, currScale);
-
-        // Zoom out until minimum scale, in specified increments designed so that the last zoom will
-        // be less than requested.
-        while (mOnUiThread.canZoomOut()) {
-            mOnUiThread.zoomBy(0.7f);
-            currScale = webViewClient.expectZoomBy(currScale, 0.7f);
-        }
-
-        // At this point, zooming out should do nothing.
-        mOnUiThread.zoomBy(0.7f);
-        assertNoScaleChange(webViewClient, currScale);
-    }
-
-    private void assertNoScaleChange(ScaleChangedWebViewClient webViewClient, float currScale) throws InterruptedException {
-        // We sleep to assert to the best of our ability
-        // that a scale change does *not* happen.
-        Thread.sleep(500);
-        assertFalse(webViewClient.onScaleChangedCalled());
-        assertEquals(currScale, mOnUiThread.getScale());
-    }
-
     @UiThreadTest
     public void testScrollBarOverlay() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -1233,88 +1118,130 @@
         startWebServer(false);
         final ChromeClient webChromeClient = new ChromeClient(mOnUiThread);
         final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        WebkitUtils.onMainThreadSync(() -> {
-            mWebView.getSettings().setJavaScriptEnabled(true);
-            mWebView.setWebChromeClient(webChromeClient);
-            mOnUiThread.loadDataAndWaitForCompletion(
-                    "<html><head></head><body onload=\"" +
-                    "document.title = " +
-                    "document.getElementById('frame').contentWindow.location.href;" +
-                    "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
-                    "text/html", null);
-        });
-        assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel(10000));
+        mOnUiThread.getSettings().setJavaScriptEnabled(true);
+        mOnUiThread.setWebChromeClient(webChromeClient);
+        mOnUiThread.loadDataAndWaitForCompletion(
+                "<html><head></head><body onload=\"" +
+                "document.title = " +
+                "document.getElementById('frame').contentWindow.location.href;" +
+                "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
+                "text/html", null);
+        assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel());
     }
 
-    @UiThreadTest
-    public void testLoadDataWithBaseUrl() throws Throwable {
+    public void testLoadDataWithBaseUrl_resolvesRelativeToBaseUrl() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
-        assertNull(mWebView.getUrl());
+        assertNull(mOnUiThread.getUrl());
         String imgUrl = TestHtmlConstants.SMALL_IMG_URL; // relative
-        // Snippet of HTML that will prevent favicon requests to the test server.
-        final String HTML_HEADER = "<html><head><link rel=\"shortcut icon\" href=\"%23\" /></head>";
 
         // Trying to resolve a relative URL against a data URL without a base URL
         // will fail and we won't make a request to the test web server.
         // By using the test web server as the base URL we expect to see a request
         // for the relative URL in the test server.
         startWebServer(false);
-        String baseUrl = mWebServer.getAssetUrl("foo.html");
-        String historyUrl = "http://www.example.com/";
+        final String baseUrl = mWebServer.getAssetUrl("foo.html");
         mWebServer.resetRequestState();
         mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
                 HTML_HEADER + "<body><img src=\"" + imgUrl + "\"/></body></html>",
-                "text/html", "UTF-8", historyUrl);
+                "text/html", "UTF-8", null);
         // Verify that the resource request makes it to the server.
         assertTrue(mWebServer.wasResourceRequested(imgUrl));
-        assertEquals(historyUrl, mWebView.getUrl());
+    }
 
+    public void testLoadDataWithBaseUrl_historyUrl() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        final String baseUrl = "http://www.baseurl.com/";
+        final String historyUrl = "http://www.example.com/";
+        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
+                SIMPLE_HTML,
+                "text/html", "UTF-8", historyUrl);
+        assertEquals(historyUrl, mOnUiThread.getUrl());
+    }
+
+    public void testLoadDataWithBaseUrl_nullHistoryUrlShowsAsAboutBlank() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Check that reported URL is "about:blank" when supplied history URL
         // is null.
-        imgUrl = TestHtmlConstants.LARGE_IMG_URL;
+        final String baseUrl = "http://www.baseurl.com/";
         mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
-                HTML_HEADER + "<body><img src=\"" + imgUrl + "\"/></body></html>",
+                SIMPLE_HTML,
                 "text/html", "UTF-8", null);
-        assertTrue(mWebServer.wasResourceRequested(imgUrl));
-        assertEquals("about:blank", mWebView.getUrl());
+        assertEquals("about:blank", mOnUiThread.getUrl());
+    }
 
+    public void testLoadDataWithBaseUrl_javascriptCanAccessOrigin() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Test that JavaScript can access content from the same origin as the base URL.
-        mWebView.getSettings().setJavaScriptEnabled(true);
+        mOnUiThread.getSettings().setJavaScriptEnabled(true);
+        startWebServer(false);
+        final String baseUrl = mWebServer.getAssetUrl("foo.html");
         final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
                 HTML_HEADER + "<body onload=\"" +
                 "document.title = document.getElementById('frame').contentWindow.location.href;" +
                 "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
                 "text/html", "UTF-8", null);
-        assertEquals(crossOriginUrl, mWebView.getTitle());
+        assertEquals(crossOriginUrl, mOnUiThread.getTitle());
+    }
 
+    public void testLoadDataWithBaseUrl_dataBaseUrlIgnoresHistoryUrl() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Check that when the base URL uses the 'data' scheme, a 'data' scheme URL is used and the
         // history URL is ignored.
-        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("data:foo",
-                HTML_HEADER + "<body>bar</body></html>", "text/html", "UTF-8",
-                historyUrl);
-        assertTrue("URL: " + mWebView.getUrl(), mWebView.getUrl().indexOf("data:text/html") == 0);
-        assertTrue("URL: " + mWebView.getUrl(), mWebView.getUrl().indexOf("bar") > 0);
+        final String baseUrl = "data:foo";
+        final String historyUrl = "http://www.example.com/";
+        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
+                SIMPLE_HTML,
+                "text/html", "UTF-8", historyUrl);
 
+        final String currentUrl = mOnUiThread.getUrl();
+        assertEquals("Current URL (" + currentUrl + ") should be a data URI", 0,
+                mOnUiThread.getUrl().indexOf("data:text/html"));
+        assertTrue("Current URL (" + currentUrl + ") should contain the simple HTML we loaded",
+                mOnUiThread.getUrl().indexOf("simple html") > 0);
+    }
+
+    public void testLoadDataWithBaseUrl_unencodedContentHttpBaseUrl() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Check that when a non-data: base URL is used, we treat the String to load as
         // a raw string and just dump it into the WebView, i.e. not decoding any URL entities.
         mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("http://www.foo.com",
                 HTML_HEADER + "<title>Hello World%21</title><body>bar</body></html>",
                 "text/html", "UTF-8", null);
-        assertEquals("Hello World%21", mWebView.getTitle());
+        assertEquals("Hello World%21", mOnUiThread.getTitle());
+    }
 
+    public void testLoadDataWithBaseUrl_urlEncodedContentDataBaseUrl() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Check that when a data: base URL is used, we treat the String to load as a data: URL
         // and run load steps such as decoding URL entities (i.e., contrary to the test case
         // above.)
         mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("data:foo",
                 HTML_HEADER + "<title>Hello World%21</title></html>", "text/html", "UTF-8", null);
-        assertEquals("Hello World!", mWebView.getTitle());
+        assertEquals("Hello World!", mOnUiThread.getTitle());
+    }
 
-        // Check the method is null input safe.
+    public void testLoadDataWithBaseUrl_nullSafe() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(null, null, null, null, null);
-        assertEquals("about:blank", mWebView.getUrl());
+        assertEquals("about:blank", mOnUiThread.getUrl());
     }
 
     private void deleteIfExists(File file) throws IOException {
@@ -1408,15 +1335,15 @@
     private static class WaitForFindResultsListener
             implements WebView.FindListener {
         private final SettableFuture<Integer> mFuture;
-        private final WebViewOnUiThread mWebViewOnUiThread;
+        private final WebView mWebView;
         private final int mMatchesWanted;
         private final String mStringWanted;
         private final boolean mRetry;
 
         public WaitForFindResultsListener(
-                WebViewOnUiThread wv, String wanted, int matches, boolean retry) {
+                WebView wv, String wanted, int matches, boolean retry) {
             mFuture = SettableFuture.create();
-            mWebViewOnUiThread = wv;
+            mWebView = wv;
             mMatchesWanted = matches;
             mStringWanted = wanted;
             mRetry = retry;
@@ -1429,10 +1356,16 @@
         @Override
         public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
                 boolean isDoneCounting) {
+            try {
+                assertEquals("WebView.FindListener callbacks should occur on the UI thread",
+                        Looper.myLooper(), Looper.getMainLooper());
+            } catch (Throwable t) {
+                mFuture.setException(t);
+            }
             if (isDoneCounting) {
                 //If mRetry set to true and matches aren't equal, call findAll again
                 if (mRetry && numberOfMatches != mMatchesWanted) {
-                    mWebViewOnUiThread.findAll(mStringWanted);
+                    mWebView.findAll(mStringWanted);
                 }
                 else {
                     mFuture.set(numberOfMatches);
@@ -1457,7 +1390,7 @@
         mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
                 + "</body></html>", "text/html", null);
 
-        WaitForFindResultsListener l = new WaitForFindResultsListener(mOnUiThread, "find", 2, true);
+        WaitForFindResultsListener l = new WaitForFindResultsListener(mWebView, "find", 2, true);
         mOnUiThread.setFindListener(l);
         mOnUiThread.findAll("find");
         assertEquals(2, (int)WebkitUtils.waitForFuture(l.future()));
@@ -1477,7 +1410,7 @@
                 "Find all instances of a word on the page and highlight them.</p>";
 
         mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p + p + "</body></html>", "text/html", null);
-        WaitForFindResultsListener l = new WaitForFindResultsListener(mOnUiThread, "all", 2, true);
+        WaitForFindResultsListener l = new WaitForFindResultsListener(mWebView, "all", 2, true);
         mOnUiThread.setFindListener(l);
 
         // highlight all the strings found and wait for all the matches to be found
@@ -2113,47 +2046,6 @@
         assertEquals(url3, copyListAfterRestore.getItemAtIndex(2).getUrl());
     }
 
-    public void testSetWebViewClient() throws Throwable {
-        if (!NullWebViewUtils.isWebViewAvailable()) {
-            return;
-        }
-        final ScaleChangedWebViewClient webViewClient = new ScaleChangedWebViewClient();
-        mOnUiThread.setWebViewClient(webViewClient);
-        startWebServer(false);
-
-        assertFalse(webViewClient.onScaleChangedCalled());
-        String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mOnUiThread.loadUrlAndWaitForCompletion(url1);
-        pollingCheckForCanZoomIn();
-
-        assertTrue(mOnUiThread.zoomIn());
-        webViewClient.waitForNextScaleChange();
-    }
-
-    public void testScaleChangeCallbackMatchesGetScale() throws Throwable {
-        if (!NullWebViewUtils.isWebViewAvailable()) {
-            return;
-        }
-        // wrap_parent layout causes extra onScaleChanged ecallbacks, so set to match_parent to
-        // suppress them.
-        mOnUiThread.setLayoutHeightToMatchParent();
-        final ScaleChangedWebViewClient webViewClient = new ScaleChangedWebViewClient();
-        mOnUiThread.setWebViewClient(webViewClient);
-        startWebServer(false);
-
-        assertFalse(webViewClient.onScaleChangedCalled());
-        String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mOnUiThread.loadUrlAndWaitForCompletion(url1);
-        pollingCheckForCanZoomIn();
-
-        assertFalse(webViewClient.onScaleChangedCalled());
-        assertTrue(mOnUiThread.zoomIn());
-        ScaleChangedState state = webViewClient.waitForNextScaleChange();
-        assertEquals(
-                "Expected onScaleChanged arg 2 (new scale) to equal view.getScale()",
-                state.mNewScale, mOnUiThread.getScale());
-    }
-
     public void testRequestChildRectangleOnScreen() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
@@ -2901,103 +2793,6 @@
         }
     }
 
-    private void pollingCheckForCanZoomIn() {
-        new PollingCheck(TEST_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return mOnUiThread.canZoomIn();
-            }
-        }.run();
-    }
-
-    static class ScaleChangedState {
-        public float mOldScale;
-        public float mNewScale;
-        public boolean mCanZoomIn;
-        public boolean mCanZoomOut;
-
-        ScaleChangedState(WebView view, float oldScale, float newScale) {
-            mOldScale = oldScale;
-            mNewScale = newScale;
-            mCanZoomIn = view.canZoomIn();
-            mCanZoomOut = view.canZoomOut();
-        }
-    }
-
-    final class ScaleChangedWebViewClient extends WaitForLoadedClient {
-        private BlockingQueue<ScaleChangedState> mCallQueue;
-
-        public ScaleChangedWebViewClient() {
-            super(mOnUiThread);
-            mCallQueue = new LinkedBlockingQueue<>();
-        }
-
-        @Override
-        public void onScaleChanged(WebView view, float oldScale, float newScale) {
-            super.onScaleChanged(view, oldScale, newScale);
-            mCallQueue.add(new ScaleChangedState(view, oldScale, newScale));
-        }
-
-        public float expectZoomBy(float currentScale, float scaleAmount) {
-            assertTrue(scaleAmount != 1.0f);
-
-            float nextScale = currentScale * scaleAmount;
-            ScaleChangedState state = waitForNextScaleChange();
-            assertEquals(currentScale, state.mOldScale);
-
-            // Check that we zoomed in the expected direction wrt. the current scale.
-            if (scaleAmount > 1.0f) {
-                assertTrue(
-                        "Expected new scale > current scale when zooming in",
-                        state.mNewScale > currentScale);
-            } else {
-                assertTrue(
-                        "Expected new scale < current scale when zooming out",
-                        state.mNewScale < currentScale);
-            }
-
-            // If we hit the zoom limit, then the new scale should be between the old scale
-            // and the expected new scale. Otherwise it should equal the expected new scale.
-            if (Math.abs(nextScale - state.mNewScale) > PAGE_SCALE_EPSILON) {
-                if (scaleAmount > 1.0f) {
-                    assertFalse(state.mCanZoomIn);
-                    assertTrue(
-                            "Expected new scale <= requested scale when zooming in past limit",
-                            state.mNewScale <= nextScale);
-                } else {
-                    assertFalse(state.mCanZoomOut);
-                    assertTrue(
-                            "Expected new scale >= requested scale when zooming out past limit",
-                            state.mNewScale >= nextScale);
-                }
-            }
-
-            return state.mNewScale;
-        }
-
-        public float expectZoomOut(float currentScale) {
-            ScaleChangedState state = waitForNextScaleChange();
-            assertEquals(currentScale, state.mOldScale);
-            assertTrue(state.mNewScale < currentScale);
-            return state.mNewScale;
-        }
-
-        public float expectZoomIn(float currentScale) {
-            ScaleChangedState state = waitForNextScaleChange();
-            assertEquals(currentScale, state.mOldScale);
-            assertTrue(state.mNewScale > currentScale);
-            return state.mNewScale;
-        }
-
-        public ScaleChangedState waitForNextScaleChange() {
-            return WebkitUtils.waitForNextQueueElement(mCallQueue);
-        }
-
-        public boolean onScaleChangedCalled() {
-            return mCallQueue.size() > 0;
-        }
-    }
-
     /**
      * This should remain functionally equivalent to
      * androidx.webkit.WebViewCompatTest#testGetSafeBrowsingPrivacyPolicyUrl. Modifications to this
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java
new file mode 100644
index 0000000..93e2cd5
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java
@@ -0,0 +1,372 @@
+/*
+ * 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.webkit.cts;
+
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
+import android.test.ActivityInstrumentationTestCase2;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.webkit.cts.WebViewSyncLoader.WaitForLoadedClient;
+
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ *  Test WebView zooming behaviour
+ */
+public class WebViewZoomTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
+    private WebView mWebView;
+    private WebViewOnUiThread mOnUiThread;
+    private ScaleChangedWebViewClient mWebViewClient;
+    private CtsTestServer mWebServer;
+
+    /**
+     * Epsilon used in page scale value comparisons.
+     */
+    private static final float PAGE_SCALE_EPSILON = 0.0001f;
+
+    public WebViewZoomTest() {
+        super("com.android.cts.webkit", WebViewCtsActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final WebViewCtsActivity activity = getActivity();
+        mWebView = activity.getWebView();
+        if (mWebView == null)
+            return;
+
+        new PollingCheck() {
+            @Override
+                protected boolean check() {
+                    return activity.hasWindowFocus();
+            }
+        }.run();
+        mOnUiThread = new WebViewOnUiThread(mWebView);
+        mWebViewClient = new ScaleChangedWebViewClient();
+        mOnUiThread.setWebViewClient(mWebViewClient);
+
+        // Pinch zoom is not supported in wrap_content layouts.
+        mOnUiThread.setLayoutHeightToMatchParent();
+
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
+        if (mWebServer != null) {
+            stopWebServer();
+        }
+        super.tearDown();
+    }
+
+    private void startWebServer(boolean secure) throws Exception {
+        assertNull(mWebServer);
+        mWebServer = new CtsTestServer(getActivity(), secure);
+    }
+
+    private void stopWebServer() throws Exception {
+        assertNotNull(mWebServer);
+        ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+        ThreadPolicy tmpPolicy = new ThreadPolicy.Builder(oldPolicy)
+                .permitNetwork()
+                .build();
+        StrictMode.setThreadPolicy(tmpPolicy);
+        mWebServer.shutdown();
+        mWebServer = null;
+        StrictMode.setThreadPolicy(oldPolicy);
+    }
+
+    private void setUpPage() throws Exception {
+        assertFalse(mWebViewClient.onScaleChangedCalled());
+        startWebServer(false);
+        mOnUiThread.loadUrlAndWaitForCompletion(
+                mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
+        pollingCheckForCanZoomIn();
+    }
+
+    public void testZoomIn() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        setUpPage();
+
+        assertTrue(mOnUiThread.zoomIn());
+        mWebViewClient.waitForNextScaleChange();
+    }
+
+    @SuppressWarnings("deprecation")
+    public void testGetZoomControls() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        WebSettings settings = mOnUiThread.getSettings();
+        assertTrue(settings.supportZoom());
+        assertNotNull(
+                "Should be able to get zoom controls when zoom is enabled",
+                WebkitUtils.onMainThreadSync(() -> { return mWebView.getZoomControls(); }));
+
+        // disable zoom support
+        settings.setSupportZoom(false);
+        assertFalse(settings.supportZoom());
+        assertNull(
+                "Should not be able to get zoom controls when zoom is disabled",
+                WebkitUtils.onMainThreadSync(() -> { return mWebView.getZoomControls(); }));
+    }
+
+    public void testInvokeZoomPicker() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        WebSettings settings = mOnUiThread.getSettings();
+        assertTrue(settings.supportZoom());
+        setUpPage();
+        WebkitUtils.onMainThreadSync(() -> mWebView.invokeZoomPicker());
+    }
+
+    public void testZoom_canNotZoomInPastMaximum() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        float currScale = mOnUiThread.getScale();
+        // Zoom in until maximum scale, in default increments.
+        while (mOnUiThread.zoomIn()) {
+            currScale = mWebViewClient.expectZoomIn(currScale);
+        }
+
+        assertFalse(mOnUiThread.zoomIn());
+        assertNoScaleChange(currScale);
+    }
+
+    public void testZoom_canNotZoomOutPastMinimum() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        float currScale = mOnUiThread.getScale();
+        // Zoom in until maximum scale, in default increments.
+        while (mOnUiThread.zoomOut()) {
+            currScale = mWebViewClient.expectZoomOut(currScale);
+        }
+
+        assertFalse(mOnUiThread.zoomOut());
+        assertNoScaleChange(currScale);
+    }
+
+    public void testCanZoomWhileZoomSupportedFalse() throws Throwable {
+        // setZoomSupported disables user controls, but not zooming via API
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        setUpPage();
+
+        WebSettings settings = mOnUiThread.getSettings();
+        settings.setSupportZoom(false);
+        assertFalse(settings.supportZoom());
+
+        float currScale = mOnUiThread.getScale();
+
+        // can zoom in or out although zoom support is disabled in web settings
+        assertTrue(mOnUiThread.zoomIn());
+        currScale = mWebViewClient.expectZoomIn(currScale);
+
+        assertTrue(mOnUiThread.zoomOut());
+        currScale = mWebViewClient.expectZoomOut(currScale);
+    }
+
+    public void testZoomByPowerOfTwoIncrements() throws Throwable {
+        // setZoomSupported disables user controls, but not zooming via API
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        setUpPage();
+        float currScale = mOnUiThread.getScale();
+
+        mOnUiThread.zoomBy(1.25f); // zoom in
+        currScale = mWebViewClient.expectZoomBy(currScale, 1.25f);
+
+        mOnUiThread.zoomBy(0.75f); // zoom out
+        currScale = mWebViewClient.expectZoomBy(currScale, 0.75f);
+    }
+
+    public void testZoomByNonPowerOfTwoIncrements() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        setUpPage();
+
+        float currScale = mOnUiThread.getScale();
+
+        // Zoom in until maximum scale, in specified increments designed so that the last zoom will
+        // be less than expected.
+        while (mOnUiThread.canZoomIn()) {
+            mOnUiThread.zoomBy(1.7f);
+            currScale = mWebViewClient.expectZoomBy(currScale, 1.7f);
+        }
+
+        // At this point, zooming in should do nothing.
+        mOnUiThread.zoomBy(1.7f);
+        assertNoScaleChange(currScale);
+
+        // Zoom out until minimum scale, in specified increments designed so that the last zoom will
+        // be less than requested.
+        while (mOnUiThread.canZoomOut()) {
+            mOnUiThread.zoomBy(0.7f);
+            currScale = mWebViewClient.expectZoomBy(currScale, 0.7f);
+        }
+
+        // At this point, zooming out should do nothing.
+        mOnUiThread.zoomBy(0.7f);
+        assertNoScaleChange(currScale);
+    }
+
+    public void testScaleChangeCallbackMatchesGetScale() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        assertFalse(mWebViewClient.onScaleChangedCalled());
+
+        setUpPage();
+
+        assertFalse(mWebViewClient.onScaleChangedCalled());
+        assertTrue(mOnUiThread.zoomIn());
+        ScaleChangedState state = mWebViewClient.waitForNextScaleChange();
+        assertEquals(
+                "Expected onScaleChanged arg 2 (new scale) to equal view.getScale()",
+                state.mNewScale, mOnUiThread.getScale());
+    }
+
+    private void assertNoScaleChange(float currScale) {
+        // We sleep to assert to the best of our ability
+        // that a scale change does *not* happen.
+        try {
+            Thread.sleep(500);
+            assertFalse(mWebViewClient.onScaleChangedCalled());
+            assertEquals(currScale, mOnUiThread.getScale());
+        } catch (InterruptedException e) {
+            fail("Interrupted");
+        }
+    }
+
+    private static final class ScaleChangedState {
+        public float mOldScale;
+        public float mNewScale;
+        public boolean mCanZoomIn;
+        public boolean mCanZoomOut;
+
+        ScaleChangedState(WebView view, float oldScale, float newScale) {
+            mOldScale = oldScale;
+            mNewScale = newScale;
+            mCanZoomIn = view.canZoomIn();
+            mCanZoomOut = view.canZoomOut();
+        }
+    }
+
+    private void pollingCheckForCanZoomIn() {
+        new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
+            @Override
+            protected boolean check() {
+                return mOnUiThread.canZoomIn();
+            }
+        }.run();
+    }
+
+    private final class ScaleChangedWebViewClient extends WaitForLoadedClient {
+        private BlockingQueue<ScaleChangedState> mCallQueue;
+
+        public ScaleChangedWebViewClient() {
+            super(mOnUiThread);
+            mCallQueue = new LinkedBlockingQueue<>();
+        }
+
+        @Override
+        public void onScaleChanged(WebView view, float oldScale, float newScale) {
+            super.onScaleChanged(view, oldScale, newScale);
+            mCallQueue.add(new ScaleChangedState(view, oldScale, newScale));
+        }
+
+        public float expectZoomBy(float currentScale, float scaleAmount) {
+            assertTrue(scaleAmount != 1.0f);
+
+            float nextScale = currentScale * scaleAmount;
+            ScaleChangedState state = waitForNextScaleChange();
+            assertEquals(currentScale, state.mOldScale);
+
+            // Check that we zoomed in the expected direction wrt. the current scale.
+            if (scaleAmount > 1.0f) {
+                assertTrue(
+                        "Expected new scale > current scale when zooming in",
+                        state.mNewScale > currentScale);
+            } else {
+                assertTrue(
+                        "Expected new scale < current scale when zooming out",
+                        state.mNewScale < currentScale);
+            }
+
+            // If we hit the zoom limit, then the new scale should be between the old scale
+            // and the expected new scale. Otherwise it should equal the expected new scale.
+            if (Math.abs(nextScale - state.mNewScale) > PAGE_SCALE_EPSILON) {
+                if (scaleAmount > 1.0f) {
+                    assertFalse(state.mCanZoomIn);
+                    assertTrue(
+                            "Expected new scale <= requested scale when zooming in past limit",
+                            state.mNewScale <= nextScale);
+                } else {
+                    assertFalse(state.mCanZoomOut);
+                    assertTrue(
+                            "Expected new scale >= requested scale when zooming out past limit",
+                            state.mNewScale >= nextScale);
+                }
+            }
+
+            return state.mNewScale;
+        }
+
+        public float expectZoomOut(float currentScale) {
+            ScaleChangedState state = waitForNextScaleChange();
+            assertEquals(currentScale, state.mOldScale);
+            assertTrue(state.mNewScale < currentScale);
+            return state.mNewScale;
+        }
+
+        public float expectZoomIn(float currentScale) {
+            ScaleChangedState state = waitForNextScaleChange();
+            assertEquals(currentScale, state.mOldScale);
+            assertTrue(state.mNewScale > currentScale);
+            return state.mNewScale;
+        }
+
+        public ScaleChangedState waitForNextScaleChange() {
+            return WebkitUtils.waitForNextQueueElement(mCallQueue);
+        }
+
+        public boolean onScaleChangedCalled() {
+            return mCallQueue.size() > 0;
+        }
+    }
+}
diff --git a/tests/tests/widget/Android.bp b/tests/tests/widget/Android.bp
new file mode 100644
index 0000000..6703c55
--- /dev/null
+++ b/tests/tests/widget/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2008 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: "CtsWidgetTestCases",
+    defaults: ["cts_defaults"],
+
+    static_libs: [
+        "androidx.annotation_annotation",
+        "android-support-test",
+        "mockito-target-minus-junit4",
+        "android-common",
+        "compatibility-device-util",
+        "ctstestrunner",
+        "platform-test-annotations",
+        "truth-prebuilt",
+    ],
+
+    libs: ["android.test.runner.stubs"],
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+
+    // TODO: Move away from using hidden platform APIs b/72044662
+    platform_apis: true,
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+
+}
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
deleted file mode 100644
index 66473af..0000000
--- a/tests/tests/widget/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2008 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
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    androidx.annotation_annotation \
-    android-support-test \
-    mockito-target-minus-junit4 \
-    android-common \
-    compatibility-device-util \
-    ctstestrunner \
-    platform-test-annotations
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsWidgetTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index e7929e0..df712eb 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -558,6 +558,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.app.Activity"
+                  android:label="Activity"
+                  android:theme="@style/WidgetAttributeTestTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.app.ActivityGroup"
             android:label="ActivityGroup" />
 
diff --git a/tests/tests/widget/res/layout/widget_attribute_layout.xml b/tests/tests/widget/res/layout/widget_attribute_layout.xml
new file mode 100644
index 0000000..f858548
--- /dev/null
+++ b/tests/tests/widget/res/layout/widget_attribute_layout.xml
@@ -0,0 +1,54 @@
+<?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
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <ProgressBar
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/progress_bar"
+        android:minWidth="7dp"
+        android:maxWidth="10dp"
+        android:progressTint="#ff00ff"
+        style="@style/ExplicitStyle1" />
+
+    <Switch android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:id="@+id/switch_view"
+          android:switchPadding="5dp"
+          style="@style/ExplicitStyle2" />
+
+    <Toolbar android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:id="@+id/toolbar_view" />
+
+    <View android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:id="@+id/view4"
+          style="?android:attr/textAppearanceLarge"/>
+
+    <Button android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/button1" />
+
+    <Button android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/button2"
+            style="@style/ExplicitStyle1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index b35ba64..3966207 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -416,4 +416,29 @@
     <style name="TextView_FontXmlResource">
         <item name="android:fontFamily">@font/samplexmlfont</item>
     </style>
+
+    <style name="WidgetAttributeTestTheme" parent="@android:Theme.Material">
+        <item name="android:toolbarStyle">@style/MyToolbarStyle</item>
+    </style>
+
+    <style name="MyToolbarStyle" parent="@style/MyToolbarStyleParent">
+        <item name="android:titleMarginEnd">3dp</item>
+    </style>
+
+    <style name="MyToolbarStyleParent">
+        <item name="android:titleMarginStart">6dp</item>
+    </style>
+
+    <style name="ExplicitStyle1" parent="@style/ParentOfExplicitStyle1">
+        <item name="android:padding">1dp</item>
+        <item name="android:progress">5</item>
+        <item name="android:max">50</item>
+    </style>
+
+    <style name="ParentOfExplicitStyle1">
+        <item name="android:paddingLeft">2dp</item>
+        <item name="android:mirrorForRtl">true</item>
+    </style>
+
+    <style name="ExplicitStyle2" />
 </resources>
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
index 49b0f64..39ddda0 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -69,6 +69,7 @@
 import android.widget.AbsListView.OnScrollListener;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
+import android.widget.EdgeEffect;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -1127,6 +1128,27 @@
         }
     }
 
+    @SmallTest
+    @UiThreadTest
+    @Test
+    public void testEdgeEffectColors() {
+        int defaultColor = new EdgeEffect(mListView.getContext()).getColor();
+        assertEquals(mListView.getTopEdgeEffectColor(), defaultColor);
+        assertEquals(mListView.getBottomEdgeEffectColor(), defaultColor);
+
+        mListView.setEdgeEffectColor(Color.BLUE);
+        assertEquals(mListView.getTopEdgeEffectColor(), Color.BLUE);
+        assertEquals(mListView.getBottomEdgeEffectColor(), Color.BLUE);
+
+        mListView.setTopEdgeEffectColor(Color.RED);
+        assertEquals(mListView.getTopEdgeEffectColor(), Color.RED);
+        assertEquals(mListView.getBottomEdgeEffectColor(), Color.BLUE);
+
+        mListView.setBottomEdgeEffectColor(Color.GREEN);
+        assertEquals(mListView.getTopEdgeEffectColor(), Color.RED);
+        assertEquals(mListView.getBottomEdgeEffectColor(), Color.GREEN);
+    }
+
     // Helper method that emulates fast scroll by dragging along the right edge of our ListView.
     private void verifyFastScroll() throws Throwable {
         setAdapter();
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
index 5b969d3..fa105c2 100644
--- a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
@@ -18,6 +18,8 @@
 
 import static com.android.compatibility.common.util.WidgetTestUtils.sameCharSequence;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -70,12 +72,17 @@
 
 import com.android.compatibility.common.util.PollingCheck;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class AutoCompleteTextViewTest {
@@ -420,6 +427,232 @@
                 false, Color.YELLOW, 1, true);
     }
 
+    @Test
+    public void refreshAutoCompleteResults_addItem() throws Throwable {
+        List<String> suggestions = new ArrayList<>(ImmutableList.of("testOne", "testTwo"));
+        mAdapter = new ArrayAdapter<String>(
+                mActivity, android.R.layout.simple_dropdown_item_1line, suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setText("testT");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testTwo");
+
+        mActivityRule.runOnUiThread(() -> {
+            mAdapter.add("testThree");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testTwo", "testThree");
+    }
+
+    @Test
+    public void refreshAutoCompleteResults_removeItem() throws Throwable {
+        List<String> suggestions = new ArrayList<>(
+                ImmutableList.of("testOne", "testTwo", "testThree"));
+        mAdapter = new ArrayAdapter<String>(
+                mActivity, android.R.layout.simple_dropdown_item_1line, suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setText("testT");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testTwo", "testThree");
+
+        mActivityRule.runOnUiThread(() -> {
+            mAdapter.remove("testThree");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testTwo");
+    }
+
+    @Test
+    public void refreshAutoCompleteResults_threshold_changeText() throws Throwable {
+        List<String> suggestions = new ArrayList<>(
+                ImmutableList.of("testOne", "testTwo", "testThree"));
+        mAdapter = new ArrayAdapter<String>(
+                mActivity, android.R.layout.simple_dropdown_item_1line, suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setThreshold(3);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setText("tes");
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Above Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setText("test");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
+
+        // At Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setText("tes");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
+
+        // Below Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setText("te");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
+    }
+
+    @Test
+    public void refreshAutoCompleteResults_changeThreshold() throws Throwable {
+        List<String> suggestions = new ArrayList<>(
+                ImmutableList.of("testOne", "testTwo", "testThree"));
+        mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
+                suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setText("test");
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Above Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setThreshold(3);
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
+
+        // At Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setThreshold(4);
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
+
+        // Below Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setThreshold(5);
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
+    }
+
+    @Test
+    public void refreshAutoCompleteResults_dropDownAlwaysVisible() throws Throwable {
+        List<String> suggestions = new ArrayList<>(
+                ImmutableList.of("testOne", "testTwo", "testThree"));
+        mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
+                suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setDropDownAlwaysVisible(true);
+            mAutoCompleteTextView.setText("test");
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Below Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setThreshold(5);
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
+    }
+
+    @Test
+    public void refreshAutoCompleteResults_dropDownNotAlwaysVisible() throws Throwable {
+        List<String> suggestions = new ArrayList<>(
+                ImmutableList.of("testOne", "testTwo", "testThree"));
+        mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
+                suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setDropDownAlwaysVisible(false);
+            mAutoCompleteTextView.setText("test");
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Below Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setThreshold(5);
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
+    }
+
+    @Test
+    public void refreshAutoCompleteResults_popupCanBeUpdated() throws Throwable {
+        List<String> suggestions = new ArrayList<>(
+                ImmutableList.of("testOne", "testTwo", "testThree"));
+        mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
+                suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setDropDownAlwaysVisible(false);
+            mAutoCompleteTextView.setText("test");
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Below Threshold.
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setThreshold(5);
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
+    }
+
+    @Test
+    public void refreshAutoCompleteResults() throws Throwable {
+        List<String> suggestions = new ArrayList<>(ImmutableList.of("testOne", "testTwo"));
+        mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
+                suggestions);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.setText("testT");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testTwo");
+
+        mActivityRule.runOnUiThread(() -> {
+            mAdapter.add("testThree");
+            mAutoCompleteTextView.refreshAutoCompleteResults();
+        });
+
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(getAutoCompleteSuggestions()).containsExactly("testTwo", "testThree");
+    }
+
     @UiThreadTest
     @Test
     public void testReplaceText() {
@@ -803,6 +1036,15 @@
         assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, mAutoCompleteTextView.getDropDownWidth());
     }
 
+    private List<Object> getAutoCompleteSuggestions() {
+        int count = mAutoCompleteTextView.getAdapter().getCount();
+        List<Object> autoCompleteSuggestions = new ArrayList<>(count);
+        for (int index = 0; index < count; index++) {
+            autoCompleteSuggestions.add(mAutoCompleteTextView.getAdapter().getItem(index));
+        }
+        return autoCompleteSuggestions;
+    }
+
     private class MockValidator implements AutoCompleteTextView.Validator {
         public CharSequence fixText(CharSequence invalidText) {
             return STRING_VALIDATED;
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
index 88aa357..3ad7ad0 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -28,6 +28,7 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
@@ -39,6 +40,7 @@
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
+import android.widget.EdgeEffect;
 import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
 import android.widget.TextView;
@@ -769,6 +771,26 @@
         assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() >= 0.0f);
     }
 
+    @UiThreadTest
+    @Test
+    public void testEdgeEffectColors() {
+        int defaultColor = new EdgeEffect(mScrollViewRegular.getContext()).getColor();
+        assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), defaultColor);
+        assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), defaultColor);
+
+        mScrollViewRegular.setEdgeEffectColor(Color.BLUE);
+        assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), Color.BLUE);
+        assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), Color.BLUE);
+
+        mScrollViewRegular.setLeftEdgeEffectColor(Color.RED);
+        assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), Color.RED);
+        assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), Color.BLUE);
+
+        mScrollViewRegular.setRightEdgeEffectColor(Color.GREEN);
+        assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), Color.RED);
+        assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), Color.GREEN);
+    }
+
     private boolean isInRange(int current, int from, int to) {
         if (from < to) {
             return current >= from && current <= to;
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index 88f3450..b53bf4f 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -388,6 +388,20 @@
     }
 
     @Test
+    public void testAccessEpicenterBounds() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+        assertNull(mPopupWindow.getEpicenterBounds());
+
+        final Rect epicenter = new Rect(5, 10, 15, 20);
+
+        mPopupWindow.setEpicenterBounds(epicenter);
+        assertEquals(mPopupWindow.getEpicenterBounds(), epicenter);
+
+        mPopupWindow.setEpicenterBounds(null);
+        assertNull(mPopupWindow.getEpicenterBounds());
+    }
+
+    @Test
     public void testAccessInputMethodMode() throws Throwable {
         mPopupWindowBuilder = new Builder().withDismissListener();
         mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index f083053..d3c685a 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -72,6 +72,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -901,6 +902,74 @@
                 () -> mPopupWindow.showAtLocation(anchorView, Gravity.BOTTOM, 0, 0), false);
     }
 
+    @Test
+    public void testEnterExitTransitionAsDropDownWithCustomBounds() throws Throwable {
+        final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+        final Rect epicenter = new Rect(20, 50, 22, 80);
+        verifyTransitionEpicenterChange(
+                () -> mPopupWindow.showAsDropDown(anchorView, 0, 0), epicenter);
+    }
+
+    private void verifyTransitionEpicenterChange(Runnable showRunnable, Rect epicenterBounds)
+            throws Throwable {
+        TransitionListener enterListener = mock(TransitionListener.class);
+        Transition enterTransition = new BaseTransition();
+        enterTransition.addListener(enterListener);
+
+        TransitionListener exitListener = mock(TransitionListener.class);
+        Transition exitTransition = new BaseTransition();
+        exitTransition.addListener(exitListener);
+
+        OnDismissListener dismissListener = mock(OnDismissListener.class);
+
+        mPopupWindow = createPopupWindow(createPopupContent(CONTENT_SIZE_DP, CONTENT_SIZE_DP));
+        mPopupWindow.setEnterTransition(enterTransition);
+        mPopupWindow.setExitTransition(exitTransition);
+        mPopupWindow.setOnDismissListener(dismissListener);
+
+        ArgumentCaptor<Transition> captor = ArgumentCaptor.forClass(Transition.class);
+
+        mActivityRule.runOnUiThread(showRunnable);
+        mInstrumentation.waitForIdleSync();
+
+        verify(enterListener, times(1)).onTransitionStart(captor.capture());
+        final Rect oldEpicenterStart = new Rect(captor.getValue().getEpicenter());
+
+        mActivityRule.runOnUiThread(mPopupWindow::dismiss);
+        mInstrumentation.waitForIdleSync();
+
+        verify(exitListener, times(1)).onTransitionStart(captor.capture());
+        final Rect oldEpicenterExit = new Rect(captor.getValue().getEpicenter());
+
+        mPopupWindow.setEpicenterBounds(epicenterBounds);
+        mActivityRule.runOnUiThread(showRunnable);
+        mInstrumentation.waitForIdleSync();
+
+        verify(enterListener, times(2)).onTransitionStart(captor.capture());
+        final Rect newEpicenterStart = new Rect(captor.getValue().getEpicenter());
+
+        mActivityRule.runOnUiThread(mPopupWindow::dismiss);
+        mInstrumentation.waitForIdleSync();
+
+        verify(exitListener, times(2)).onTransitionStart(captor.capture());
+
+        final Rect newEpicenterExit = new Rect(captor.getValue().getEpicenter());
+
+        verifyEpicenters(oldEpicenterStart, newEpicenterStart, epicenterBounds);
+        verifyEpicenters(oldEpicenterExit, newEpicenterExit, epicenterBounds);
+
+    }
+
+    private void verifyEpicenters(Rect actualOld, Rect actualNew, Rect passed) {
+        Rect oldCopy = new Rect(actualOld);
+        int left = oldCopy.left;
+        int top = oldCopy.top;
+        oldCopy.set(passed);
+        oldCopy.offset(left, top);
+
+        assertEquals(oldCopy, actualNew);
+    }
+
     private void verifyEnterExitTransition(Runnable showRunnable, boolean showAgain)
             throws Throwable {
         TransitionListener enterListener = mock(TransitionListener.class);
@@ -1139,6 +1208,47 @@
     }
 
     @Test
+    public void testAccessClippingToScreenEnabled() {
+        mPopupWindow = new PopupWindow(mActivity);
+        assertFalse(mPopupWindow.isClipToScreenEnabled());
+
+        mPopupWindow.setClipToScreenEnabled(true);
+        assertTrue(mPopupWindow.isClipToScreenEnabled());
+    }
+
+    @Test
+    public void testAccessLayoutInScreenEnabled() {
+        mPopupWindow = new PopupWindow(mActivity);
+        assertFalse(mPopupWindow.isLayoutInScreenEnabled());
+
+        mPopupWindow.setLayoutInScreenEnabled(true);
+        assertTrue(mPopupWindow.isLayoutInScreenEnabled());
+    }
+
+    @Test
+    public void testAccessTouchModal() {
+        mPopupWindow = new PopupWindow(mActivity);
+        assertTrue(mPopupWindow.isTouchModal());
+
+        mPopupWindow.setTouchModal(false);
+        assertFalse(mPopupWindow.isTouchModal());
+    }
+
+    @Test
+    public void testAccessEpicenterBounds() {
+        mPopupWindow = new PopupWindow(mActivity);
+        assertNull(mPopupWindow.getEpicenterBounds());
+
+        final Rect epicenter = new Rect(5, 10, 15, 20);
+
+        mPopupWindow.setEpicenterBounds(epicenter);
+        assertEquals(mPopupWindow.getEpicenterBounds(), epicenter);
+
+        mPopupWindow.setEpicenterBounds(null);
+        assertNull(mPopupWindow.getEpicenterBounds());
+    }
+
+    @Test
     public void testAccessOutsideTouchable() {
         mPopupWindow = new PopupWindow(mActivity);
         assertFalse(mPopupWindow.isOutsideTouchable());
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
index 5a68273..d84a229 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -220,6 +220,20 @@
 
     @UiThreadTest
     @Test
+    public void testAccessCurrentDrawable() {
+        final Drawable progressDrawable = new ColorDrawable(Color.BLUE);
+        final Drawable indeterminateDrawable = new ColorDrawable(Color.RED);
+        mProgressBarHorizontal.setProgressDrawable(progressDrawable);
+        mProgressBarHorizontal.setIndeterminateDrawable(indeterminateDrawable);
+
+        mProgressBarHorizontal.setIndeterminate(false);
+        assertSame(progressDrawable, mProgressBarHorizontal.getCurrentDrawable());
+        mProgressBarHorizontal.setIndeterminate(true);
+        assertSame(indeterminateDrawable, mProgressBarHorizontal.getCurrentDrawable());
+    }
+
+    @UiThreadTest
+    @Test
     public void testAccessProgress() {
         assertEquals(0, mProgressBarHorizontal.getProgress());
 
@@ -559,6 +573,38 @@
         assertEquals(oldSecondaryProgress, mProgressBarHorizontal.getSecondaryProgress());
     }
 
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMinWidth() {
+        final int minWidth = 20;
+        mProgressBar.setMinWidth(minWidth);
+        assertEquals(minWidth, mProgressBar.getMinWidth());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMaxWidth() {
+        final int maxWidth = 20;
+        mProgressBar.setMaxWidth(maxWidth);
+        assertEquals(maxWidth, mProgressBar.getMaxWidth());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMinHeight() {
+        final int minHeight = 20;
+        mProgressBar.setMinHeight(minHeight);
+        assertEquals(minHeight, mProgressBar.getMinHeight());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMaxHeight() {
+        final int maxHeight = 20;
+        mProgressBar.setMaxHeight(maxHeight);
+        assertEquals(maxHeight, mProgressBar.getMaxHeight());
+    }
+
     /*
      * Mock class for ProgressBar to test protected methods
      */
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index 3abb023..05944c4 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -28,6 +28,7 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
@@ -39,6 +40,7 @@
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
+import android.widget.EdgeEffect;
 import android.widget.FrameLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
@@ -800,6 +802,42 @@
         assertTrue(myScrollView.getBottomFadingEdgeStrength() >= 0.0f);
     }
 
+    @Test
+    public void testScrollDescendant() throws Throwable {
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
+
+        View lastChild = mScrollViewCustom.findViewById(R.id.last_child);
+        int lastChildTop = (ITEM_COUNT - 1) * mItemHeight;
+
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.scrollToDescendant(lastChild));
+        // smoothScrollBy doesn't scroll in X
+        pollingCheckSmoothScrolling(0, 0, 0, lastChildTop);
+
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(lastChildTop, mScrollViewCustom.getScrollY());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testEdgeEffectColors() {
+        int defaultColor = new EdgeEffect(mScrollViewRegular.getContext()).getColor();
+        assertEquals(mScrollViewRegular.getTopEdgeEffectColor(), defaultColor);
+        assertEquals(mScrollViewRegular.getBottomEdgeEffectColor(), defaultColor);
+
+        mScrollViewRegular.setEdgeEffectColor(Color.BLUE);
+        assertEquals(mScrollViewRegular.getTopEdgeEffectColor(), Color.BLUE);
+        assertEquals(mScrollViewRegular.getBottomEdgeEffectColor(), Color.BLUE);
+
+        mScrollViewRegular.setTopEdgeEffectColor(Color.RED);
+        assertEquals(mScrollViewRegular.getTopEdgeEffectColor(), Color.RED);
+        assertEquals(mScrollViewRegular.getBottomEdgeEffectColor(), Color.BLUE);
+
+        mScrollViewRegular.setBottomEdgeEffectColor(Color.GREEN);
+        assertEquals(mScrollViewRegular.getTopEdgeEffectColor(), Color.RED);
+        assertEquals(mScrollViewRegular.getBottomEdgeEffectColor(), Color.GREEN);
+    }
+
     private boolean isInRange(int current, int from, int to) {
         if (from < to) {
             return current >= from && current <= to;
diff --git a/tests/tests/widget/src/android/widget/cts/WidgetAttributeTest.kt b/tests/tests/widget/src/android/widget/cts/WidgetAttributeTest.kt
new file mode 100644
index 0000000..071a0ae
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/WidgetAttributeTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.widget.cts
+
+import android.app.Activity
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.MediumTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import android.support.test.uiautomator.UiDevice
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import android.widget.ProgressBar
+import android.widget.Switch
+import android.widget.Toolbar
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class WidgetAttributeTest {
+    companion object {
+        const val DISABLE_SHELL_COMMAND =
+                "settings delete global debug_view_attributes_application_package"
+        const val ENABLE_SHELL_COMMAND =
+                "settings put global debug_view_attributes_application_package android.widget.cts"
+    }
+
+    @get:Rule
+    val activityRule = ActivityTestRule<Activity>(Activity::class.java, true, false)
+    private lateinit var uiDevice: UiDevice
+
+    @Before
+    fun setUp() {
+        uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+        uiDevice.executeShellCommand(ENABLE_SHELL_COMMAND)
+        activityRule.launchActivity(null)
+    }
+
+    @After
+    fun tearDown() {
+        uiDevice.executeShellCommand(DISABLE_SHELL_COMMAND)
+    }
+
+    @Test
+    fun testGetAttributeSourceResourceMap() {
+        val inflater = LayoutInflater.from(activityRule.getActivity())
+        val rootView = inflater.inflate(R.layout.widget_attribute_layout, null) as LinearLayout
+
+        // ProgressBar that has an explicit style ExplicitStyle1 set via style = ...
+        val progressBar = rootView.findViewById<ProgressBar>(R.id.progress_bar)
+        val attributeMapProgressBar = progressBar!!.attributeSourceResourceMap
+        assertEquals(R.layout.widget_attribute_layout,
+                attributeMapProgressBar[android.R.attr.minWidth]!!.toInt())
+        assertEquals(R.layout.widget_attribute_layout,
+                attributeMapProgressBar[android.R.attr.maxWidth]!!.toInt())
+        assertEquals(R.layout.widget_attribute_layout,
+                attributeMapProgressBar[android.R.attr.progressTint]!!.toInt())
+        assertEquals(R.style.ExplicitStyle1,
+                attributeMapProgressBar[android.R.attr.progress]!!.toInt())
+        assertEquals(R.style.ExplicitStyle1,
+                attributeMapProgressBar[android.R.attr.padding]!!.toInt())
+        assertEquals(R.style.ExplicitStyle1,
+                attributeMapProgressBar[android.R.attr.max]!!.toInt())
+        assertEquals(R.style.ParentOfExplicitStyle1,
+                attributeMapProgressBar[android.R.attr.mirrorForRtl]!!.toInt())
+
+        // Switch that has an explicit style ExplicitStyle2 set via style = ...
+        val switch = rootView.findViewById<Switch>(R.id.switch_view)
+        val attributeMapSwitch = switch!!.attributeSourceResourceMap
+        assertEquals(R.layout.widget_attribute_layout,
+                attributeMapSwitch[android.R.attr.switchPadding]!!.toInt())
+
+        // Toolbar that has MyToolbarStyle set via the theme android:toolbarStyle = ...
+        val toolbar = rootView.findViewById<Toolbar>(R.id.toolbar_view)
+        val attributeMapToobar = toolbar!!.attributeSourceResourceMap
+        assertEquals(R.style.MyToolbarStyle,
+                attributeMapToobar[android.R.attr.titleMarginEnd]!!.toInt())
+        assertEquals(R.style.MyToolbarStyleParent,
+                attributeMapToobar[android.R.attr.titleMarginStart]!!.toInt())
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/wrap/nowrap/Android.mk b/tests/tests/wrap/nowrap/Android.mk
index 8fd1015..094f0f0 100644
--- a/tests/tests/wrap/nowrap/Android.mk
+++ b/tests/tests/wrap/nowrap/Android.mk
@@ -35,4 +35,6 @@
 # Jarjar to make WrapTest unique.
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_PACKAGE)
diff --git a/tests/tests/wrap/wrap_debug/Android.mk b/tests/tests/wrap/wrap_debug/Android.mk
index c67e191..71c517b 100644
--- a/tests/tests/wrap/wrap_debug/Android.mk
+++ b/tests/tests/wrap/wrap_debug/Android.mk
@@ -42,6 +42,8 @@
 # Jarjar to make WrapTest unique.
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_PACKAGE)
 
 include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
index b768dcf..b2d4ae4 100644
--- a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
@@ -42,6 +42,8 @@
 # Jarjar to make WrapTest unique.
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_PACKAGE)
 
 include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_nodebug/Android.mk b/tests/tests/wrap/wrap_nodebug/Android.mk
index 3317f3c..87dc828 100644
--- a/tests/tests/wrap/wrap_nodebug/Android.mk
+++ b/tests/tests/wrap/wrap_nodebug/Android.mk
@@ -42,6 +42,8 @@
 # Jarjar to make WrapTest unique.
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
 include $(BUILD_PACKAGE)
 
 include $(CLEAR_VARS)
diff --git a/tests/vr/AndroidTest.xml b/tests/vr/AndroidTest.xml
index 0212be6..ee9d9cb 100644
--- a/tests/vr/AndroidTest.xml
+++ b/tests/vr/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS VR test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="vr" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsVrTestCases.apk" />