Merge "Skip SystemUpdatePolicy Tests"
diff --git a/apps/CameraITS/tests/scene0/test_test_patterns.py b/apps/CameraITS/tests/scene0/test_test_patterns.py
index a1d9cb8..48d464d 100644
--- a/apps/CameraITS/tests/scene0/test_test_patterns.py
+++ b/apps/CameraITS/tests/scene0/test_test_patterns.py
@@ -21,7 +21,7 @@
 import numpy as np
 
 NAME = os.path.basename(__file__).split('.')[0]
-PATTERNS = [1, 2]
+CHECKED_PATTERNS = [1, 2]  # [SOLID_COLOR, COLOR_BARS]
 COLOR_BAR_ORDER = ['WHITE', 'YELLOW', 'CYAN', 'GREEN', 'MAGENTA', 'RED',
                    'BLUE', 'BLACK']
 COLOR_CHECKER = {'BLACK': [0, 0, 0], 'RED': [1, 0, 0], 'GREEN': [0, 1, 0],
@@ -29,6 +29,7 @@
                  'YELLOW': [1, 1, 0], 'WHITE': [1, 1, 1]}
 CH_TOL = 2E-3  # 1/2 DN in [0:1]
 LSFR_COEFFS = 0b100010000  # PN9
+REQUIRED_PATTERNS = [2]  # [COLOR_BARS]
 
 
 def check_solid_color(cap, props):
@@ -127,7 +128,7 @@
     sens_min, _ = props['android.sensor.info.sensitivityRange']
     exposure = min(props['android.sensor.info.exposureTimeRange'])
 
-    for pattern in PATTERNS:
+    for pattern in CHECKED_PATTERNS:
         if pattern in avail_patterns:
             req = its.objects.manual_capture_request(int(sens_min),
                                                      exposure)
@@ -143,7 +144,11 @@
             # Check pattern for correctness
             assert check_pattern(cap, props, pattern)
         else:
-            print 'Pattern not in android.sensor.availableTestPatternModes.'
+            print '%d not in android.sensor.availableTestPatternModes.' % (
+                    pattern)
+    msg = 'avail_patterns: %s, REQUIRED_PATTERNS: %s' % (
+            str(avail_patterns), str(REQUIRED_PATTERNS))
+    assert set(REQUIRED_PATTERNS).issubset(avail_patterns), msg
 
 
 def main():
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index d630e1a..34b6192 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -90,11 +90,11 @@
 }
 
 # Not yet mandated tests ['test', first_api_level mandatory]
-# ie. ['test_test_patterns', 28] is MANDATED for first_api_level >= 28
+# ie. ['test_test_patterns', 30] is MANDATED for first_api_level >= 30
 NOT_YET_MANDATED = {
         'scene0': [
-                ['test_test_patterns', 28],
-                ['test_tonemap_curve', 28]
+                ['test_test_patterns', 30],
+                ['test_tonemap_curve', 30]
         ],
         'scene1_1': [
                 ['test_ae_precapture_trigger', 28],
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 5e618a1..be3dd9b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -56,6 +56,7 @@
     <uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
     <uses-feature android:name="android.software.companion_device_setup" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index 62eadbe..776ac1b 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -19,11 +19,15 @@
 }
 
 # ensure we keep public camera test methods, these are needed at runtime
--keepclassmembers class * extends android.hardware.camera2.cts.testcases.Camera2AndroidBasicTestCase {
+-keepclassmembers class android.hardware.camera2.cts.PerformanceTest {
     public <methods>;
 }
 
--keepclassmembers class * extends android.hardware.cts.CameraTestCase {
+-keepclassmembers class android.hardware.cts.LegacyCameraPerformanceTest {
+    public <methods>;
+}
+
+-keepclassmembers class org.junit.runners.JUnit4 {
     public <methods>;
 }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 636dc2b..24e273c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.verifier.audio;
 
+import android.content.Context;
 import android.media.*;
 import android.media.audiofx.AcousticEchoCanceler;
 import android.os.Bundle;
@@ -61,8 +62,10 @@
     private final int CORRELATION_DURATION_MS = TEST_DURATION_MS - 3000;
     private final int SHOT_COUNT_CORRELATION = CORRELATION_DURATION_MS/SHOT_FREQUENCY_MS;
     private final int SHOT_COUNT = TEST_DURATION_MS/SHOT_FREQUENCY_MS;
+    private final float MIN_RMS_DB = -60.0f; //dB
+    private final float MIN_RMS_VAL = (float)Math.pow(10,(MIN_RMS_DB/20));
 
-    private final double TEST_THRESHOLD_AEC_ON = 0.4; //From SoloTester
+    private final double TEST_THRESHOLD_AEC_ON = 0.5;
     private final double TEST_THRESHOLD_AEC_OFF = 0.6;
     private RmsHelper mRMSRecorder1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
     private RmsHelper mRMSRecorder2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
@@ -131,6 +134,9 @@
                         count++;
                     }
                     float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
+                    if (rms < MIN_RMS_VAL) {
+                        rms = MIN_RMS_VAL;
+                    }
 
                     double alpha = 0.9;
                     double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
@@ -162,9 +168,10 @@
             DspBufferDouble crossCorr = new DspBufferDouble(actualLen);
 
             for (int i = firstShot, index = 0; i <= lastShot; ++i, ++index) {
-                double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), -120);
+                double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), MIN_RMS_DB);
                 rmsPlayerdB.setValue(index, valPlayerdB);
-                double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]), -120);
+                double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]),
+                        MIN_RMS_DB);
                 rmsRecorderdB.setValue(index, valRecorderdB);
             }
 
@@ -288,20 +295,37 @@
                     return;
                 }
 
-                int playbackStreamType = AudioManager.STREAM_MUSIC;
+                 //Step 0. Prepare system
+                AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+                int targetMode = AudioManager.MODE_IN_COMMUNICATION;
+                int originalMode = am.getMode();
+                am.setMode(targetMode);
+
+                if (am.getMode() != targetMode) {
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
+                            "Couldn't set mode to MODE_IN_COMMUNICATION.");
+                    return;
+                }
+
+                int playbackStreamType = AudioManager.STREAM_VOICE_CALL;
                 int maxLevel = getMaxLevelForStream(playbackStreamType);
                 int desiredLevel = maxLevel - 1;
                 setLevelForStream(playbackStreamType, desiredLevel);
 
                 int currentLevel = getLevelForStream(playbackStreamType);
                 if (currentLevel != desiredLevel) {
+                    am.setMode(originalMode);
                     sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
-                            "Couldn't set level for STREAM_MUSIC. Expected " +
+                            "Couldn't set level for STREAM_VOICE_CALL. Expected " +
                                     desiredLevel +" got: " + currentLevel);
                     return;
                 }
 
+                boolean originalSpeakerPhone = am.isSpeakerphoneOn();
+                am.setSpeakerphoneOn(true);
+
                 //Step 1. With AEC (on by Default when using VOICE_COMMUNICATION audio source).
+                mSPlayer.setStreamType(playbackStreamType);
                 mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.speech);
                 mSRecorder.startRecording();
 
@@ -316,16 +340,20 @@
                 } catch (Exception e) {
                     mSRecorder.stopRecording();
                     String msg = "Could not create AEC Effect. " + e.toString();
-                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     recordTestResults(mMandatory, 0, 0, msg);
+                    am.setSpeakerphoneOn(originalSpeakerPhone);
+                    am.setMode(originalMode);
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     return;
                 }
 
                 if (mAec == null) {
                     mSRecorder.stopRecording();
                     String msg = "Could not create AEC Effect (AEC Null)";
-                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     recordTestResults(mMandatory,0, 0, msg);
+                    am.setSpeakerphoneOn(originalSpeakerPhone);
+                    am.setMode(originalMode);
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                     return;
                 }
 
@@ -333,8 +361,10 @@
                     String msg = "AEC is not enabled by default.";
                     if (mMandatory) {
                         mSRecorder.stopRecording();
-                        sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                         recordTestResults(mMandatory,0, 0, msg);
+                        am.setSpeakerphoneOn(originalSpeakerPhone);
+                        am.setMode(originalMode);
+                        sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
                         return;
                     } else {
                         sb.append("Warning. " + msg + "\n");
@@ -358,9 +388,9 @@
                                     20 * Math.log10(mRMSPlayer1.getRmsCurrent())));
                 }
 
-                mSPlayer.play(false);
                 mRMSPlayer1.setRunning(false);
                 mRMSRecorder1.setRunning(false);
+                mSPlayer.play(false);
 
                 int lastShot = SHOT_COUNT - 1;
                 int firstShot = SHOT_COUNT - SHOT_COUNT_CORRELATION;
@@ -397,10 +427,13 @@
                                     20 * Math.log10(mRMSPlayer2.getRmsCurrent())));
                 }
 
-                mSRecorder.stopRecording();
-                mSPlayer.play(false);
                 mRMSPlayer2.setRunning(false);
                 mRMSRecorder2.setRunning(false);
+                mSRecorder.stopRecording();
+                mSPlayer.play(false);
+
+                am.setSpeakerphoneOn(originalSpeakerPhone);
+                am.setMode(originalMode);
 
                 double maxNoAEC = computeAcousticCouplingFactor(mRMSPlayer2.getRmsSnapshots(),
                         mRMSRecorder2.getRmsSnapshots(), firstShot, lastShot);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
index 26597c3..340b09b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
@@ -18,8 +18,6 @@
 
 import android.Manifest;
 import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
 import android.app.KeyguardManager;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -30,6 +28,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
+import android.provider.Settings;
 import android.text.InputType;
 import android.util.Log;
 import android.view.View;
@@ -54,7 +53,6 @@
 public class BiometricTest extends PassFailButtons.Activity {
 
     private static final String TAG = "BiometricTest";
-    private static final String BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL";
     private static final int BIOMETRIC_PERMISSION_REQUEST_CODE = 0;
 
     // Test that BiometricPrompt setAllowDeviceCredentials returns ERROR_NO_DEVICE_CREDENTIAL when
@@ -183,7 +181,9 @@
             });
             mButtonEnroll.setOnClickListener((view) -> {
                 final Intent intent = new Intent();
-                intent.setAction(BIOMETRIC_ENROLL);
+                intent.setAction(Settings.ACTION_BIOMETRIC_ENROLL);
+                intent.putExtra(Settings.EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED,
+                        BiometricManager.Authenticators.BIOMETRIC_STRONG);
                 startActivity(intent);
             });
             mButtonTestCredential.setOnClickListener((view) -> {
@@ -234,6 +234,9 @@
         } else if (testType == TEST_AUTHENTICATE) {
             if (result == BiometricManager.BIOMETRIC_SUCCESS) {
                 showBiometricPrompt(false /* allowCredential */);
+            } else if (result == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) {
+                showToastAndLog("No biometric features, test passed.");
+                getPassButton().setEnabled(true);
             } else {
                 showToastAndLog("Error: " + result +
                         " Please ensure at least one biometric is enrolled and try again");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
index b62c2c1..fd38e98 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
@@ -43,7 +43,7 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.TotalCaptureResult;
 import android.media.Image;
@@ -126,7 +126,7 @@
     private CaptureRequest.Builder mStillCaptureRequestBuilder;
     private CaptureRequest mStillCaptureRequest;
 
-    private HashMap<String, ArrayList<CapabilityAndMaxSize>> mTestCases = new HashMap<>();
+    private HashMap<String, ArrayList<Capability>> mTestCases = new HashMap<>();
     private int mCurrentCameraIndex = -1;
     private String mCameraId;
     private CameraCaptureSession mCaptureSession;
@@ -221,19 +221,16 @@
             for (String id : mCameraIdList) {
                 CameraCharacteristics characteristics =
                         mCameraManager.getCameraCharacteristics(id);
-                Key<CapabilityAndMaxSize[]> key =
+                Key<Capability[]> key =
                         CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES;
-                CapabilityAndMaxSize[] bokehCaps = characteristics.get(key);
+                Capability[] bokehCaps = characteristics.get(key);
 
                 if (bokehCaps == null) {
                     continue;
-                } else if (bokehCaps.length == 1 &&
-                        bokehCaps[0].getMode() == CameraMetadata.CONTROL_BOKEH_MODE_OFF) {
-                    continue;
                 }
 
-                ArrayList<CapabilityAndMaxSize> nonOffModes = new ArrayList<>();
-                for (CapabilityAndMaxSize bokehCap : bokehCaps) {
+                ArrayList<Capability> nonOffModes = new ArrayList<>();
+                for (Capability bokehCap : bokehCaps) {
                     int mode = bokehCap.getMode();
                     if (mode == CameraMetadata.CONTROL_BOKEH_MODE_STILL_CAPTURE ||
                             mode == CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS) {
@@ -329,8 +326,8 @@
         // There is untested combination for the current camera, set the next untested combination.
         mNextCombination = combination.get();
         int nextMode = mNextCombination.mMode;
-        ArrayList<CapabilityAndMaxSize> bokehCaps = mTestCases.get(mCameraId);
-        for (CapabilityAndMaxSize cap : bokehCaps) {
+        ArrayList<Capability> bokehCaps = mTestCases.get(mCameraId);
+        for (Capability cap : bokehCaps) {
             if (cap.getMode() == nextMode) {
                 mMaxBokehStreamingSize = cap.getMaxStreamingSize();
             }
@@ -619,8 +616,8 @@
         }
 
         // Update untested entries
-        ArrayList<CapabilityAndMaxSize> currentTestCase = mTestCases.get(mCameraId);
-        for (CapabilityAndMaxSize bokehCap : currentTestCase) {
+        ArrayList<Capability> currentTestCase = mTestCases.get(mCameraId);
+        for (Capability bokehCap : currentTestCase) {
             Size maxStreamingSize = bokehCap.getMaxStreamingSize();
             Size previewSize;
             if ((maxStreamingSize.getWidth() == 0 && maxStreamingSize.getHeight() == 0) ||
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/performance/CameraPerformanceActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/performance/CameraPerformanceActivity.java
index 59b7a03..41b8569 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/performance/CameraPerformanceActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/performance/CameraPerformanceActivity.java
@@ -21,8 +21,6 @@
 import android.app.ProgressDialog;
 import android.content.Context;
 import android.hardware.camera2.cts.PerformanceTest;
-import android.hardware.camera2.cts.testcases.Camera2AndroidBasicTestCase;
-import android.hardware.cts.CameraTestCase;
 import android.hardware.cts.LegacyCameraPerformanceTest;
 import android.os.Bundle;
 import android.util.Log;
@@ -35,12 +33,9 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestResult;
 
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
 import org.junit.runner.Description;
 import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
 import org.junit.runner.Result;
 import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunListener;
@@ -48,7 +43,6 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
@@ -67,7 +61,7 @@
     private CameraTestInstrumentation mCameraInstrumentation = new CameraTestInstrumentation();
     private Instrumentation mCachedInstrumentation;
     private Bundle mCachedInstrumentationArgs;
-    private HashMap<String, TestCase> mTestCaseMap = new HashMap<String, TestCase>();
+    private HashMap<String, Class> mTestCaseMap = new HashMap<String, Class>();
     private ProgressDialog mSpinnerDialog;
     private AlertDialog mResultDialog;
     private ArrayList<Metric> mResults = new ArrayList<Metric>();
@@ -77,10 +71,12 @@
                 R.string.camera_performance_test_info, R.string.camera_performance_test_info);
     }
 
-    private void executeTest(TestCase testCase) {
+    private void executeTest(Class testClass, String testName) {
         JUnitCore testRunner = new JUnitCore();
+        Log.v(TAG, String.format("Execute Test: %s#%s", testClass.getSimpleName(), testName));
+        Request request = Request.method(testClass, testName);
         testRunner.addListener(new CameraRunListener());
-        testRunner.run(testCase);
+        testRunner.run(request);
     }
 
     private class MetricListener implements CameraTestInstrumentation.MetricListener {
@@ -124,8 +120,8 @@
                         StringBuilder message = new StringBuilder();
                         for (Metric m : mResults) {
                             message.append(String.format("%s : %5.2f %s\n",
-                                        m.getMessage().replaceAll("_", " "), m.getValues()[0],
-                                        m.getUnit()));
+                                    m.getMessage().replaceAll("_", " "), m.getValues()[0],
+                                    m.getUnit()));
                         }
                         mResultDialog.setMessage(message);
                         mResultDialog.show();
@@ -193,42 +189,15 @@
     }
 
     private void initializeTestCases(Context ctx) {
-        TestSuite suite = new TestSuite(TEST_CLASSES);
-        Enumeration<Test> testSuite = suite.tests();
-        while (testSuite.hasMoreElements()) {
-            Test s = testSuite.nextElement();
-            if (s instanceof TestSuite) {
-                Enumeration<Test> tests = ((TestSuite) s).tests();
-                while (tests.hasMoreElements()) {
-                    Test test = tests.nextElement();
-                    if (test instanceof Camera2AndroidBasicTestCase) {
-                        Camera2AndroidBasicTestCase testCase = (Camera2AndroidBasicTestCase) test;
-
-                        // The base case class has one internal test that can
-                        // be ignored for the purpose of this test activity.
-                        try {
-                            Method method = testCase.getClass().getMethod(testCase.getName());
-                            Annotation an = method.getAnnotation(
-                                    android.test.suitebuilder.annotation.Suppress.class);
-                            if (an != null) {
-                                continue;
-                            }
-                        } catch (Exception e) {
-                            e.printStackTrace();
-                            continue;
-                        }
-
-                        testCase.setContext(ctx);
-                        mTestCaseMap.put(testCase.getName(), testCase);
-                    } else if (test instanceof CameraTestCase) {
-                        TestCase testCase = (CameraTestCase) test;
-                        mTestCaseMap.put(testCase.getName(), testCase);
-                    } else {
-                        Log.d(TAG, "Test is not instance of any known camera test cases");
-                    }
+        for (Class testClass : TEST_CLASSES) {
+            Log.v(TAG, String.format("Test class: %s", testClass.getSimpleName()));
+            for (Method method : testClass.getMethods()) {
+                Annotation an = method.getAnnotation((Class) org.junit.Test.class);
+                Log.v(TAG, String.format("Test method: %s; Annotation: %s", method.getName(), an));
+                if (an == null) {
+                    continue;
                 }
-            } else {
-                Log.d(TAG, "Test is not instance of TestSuite");
+                mTestCaseMap.put(method.getName(), testClass);
             }
         }
     }
@@ -264,8 +233,8 @@
 
         @Override
         public void performTest(DialogTestListActivity activity) {
-            TestCase testCase = mTestCaseMap.get(mTestId);
-            if (testCase == null) {
+            Class testClass = mTestCaseMap.get(mTestId);
+            if (testClass == null) {
                 Log.e(TAG, "Test case with name: " + mTestId + " not found!");
                 return;
             }
@@ -273,7 +242,7 @@
             mExecutorService.execute(new Runnable() {
                 @Override
                 public void run() {
-                    executeTest(testCase);
+                    executeTest(testClass, mTestId);
                 }
             });
         }
@@ -318,4 +287,4 @@
         }
         mCameraInstrumentation.release();
     }
-}
+}
\ No newline at end of file
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
index 360c078..bb27360 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
@@ -23,11 +23,16 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.ResultReceiver;
 import android.util.Log;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * A service to handle interactions with the BlockedNumberProvider. The BlockedNumberProvider
  * can only be accessed by the primary user. This service can be run as a singleton service
@@ -41,11 +46,14 @@
     static final String PHONE_NUMBER_EXTRA = "number";
     static final String URI_EXTRA = "uri";
     static final String ROWS_EXTRA = "rows";
+    static final String FAIL_EXTRA = "fail";
     static final String RESULT_RECEIVER_EXTRA = "resultReceiver";
 
     private static final String TAG = "CtsBlockNumberSvc";
+    private static final int ASYNC_TIMEOUT = 10000;
 
     private ContentResolver mContentResolver;
+    private Handler mHandler = new Handler();
 
     public BlockedNumberService() {
         super(BlockedNumberService.class.getName());
@@ -77,14 +85,37 @@
     private Bundle insertBlockedNumber(String number) {
         Log.i(TAG, "insertBlockedNumber: " + number);
 
+        CountDownLatch blockedNumberLatch = getBlockedNumberLatch();
         ContentValues cv = new ContentValues();
         cv.put(COLUMN_ORIGINAL_NUMBER, number);
         Uri uri = mContentResolver.insert(CONTENT_URI, cv);
         Bundle bundle = new Bundle();
         bundle.putString(URI_EXTRA, uri.toString());
+
+        // Wait for the content provider to be updated.
+        try {
+            blockedNumberLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            bundle.putBoolean(FAIL_EXTRA, true);
+        }
         return bundle;
     }
 
+    private CountDownLatch getBlockedNumberLatch() {
+        CountDownLatch changeLatch = new CountDownLatch(1);
+        getContentResolver().registerContentObserver(
+                CONTENT_URI, true,
+                    new ContentObserver(mHandler) {
+                        @Override
+                        public void onChange(boolean selfChange, Uri uri) {
+                            getContentResolver().unregisterContentObserver(this);
+                            changeLatch.countDown();
+                            super.onChange(selfChange);
+                        }
+                    });
+        return changeLatch;
+    }
+
     private Bundle deleteBlockedNumber(Uri uri) {
         Log.i(TAG, "deleteBlockedNumber: " + uri);
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
index e5a0ce4..91959d5 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
@@ -51,7 +51,11 @@
         Intent intent = new Intent(INSERT_ACTION);
         intent.putExtra(PHONE_NUMBER_EXTRA, phoneNumber);
 
-        return Uri.parse(runBlockedNumberService(context, intent).getString(URI_EXTRA));
+        Bundle result = runBlockedNumberService(context, intent);
+        if (result.getBoolean(BlockedNumberService.FAIL_EXTRA)) {
+            return null;
+        }
+        return Uri.parse(result.getString(URI_EXTRA));
     }
 
     /** Remove a number from the blocked number provider and returns the number of rows deleted. */
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceConfigStateManager.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceConfigStateManager.java
index 040641c..6875ae1 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceConfigStateManager.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceConfigStateManager.java
@@ -26,8 +26,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.google.common.base.Preconditions;
-
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -52,9 +51,9 @@
             @NonNull String key) {
         debug("DeviceConfigStateManager", "namespace=%s, key=%s", namespace, key);
 
-        mContext = Preconditions.checkNotNull(context);
-        mNamespace = Preconditions.checkNotNull(namespace);
-        mKey = Preconditions.checkNotNull(key);
+        mContext = Objects.requireNonNull(context);
+        mNamespace = Objects.requireNonNull(namespace);
+        mKey = Objects.requireNonNull(key);
     }
 
     @Override
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/OneTimeDeviceConfigListener.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/OneTimeDeviceConfigListener.java
index e5be3f41..3581764 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/OneTimeDeviceConfigListener.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/OneTimeDeviceConfigListener.java
@@ -23,8 +23,7 @@
 
 import androidx.annotation.NonNull;
 
-import com.google.common.base.Preconditions;
-
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -50,8 +49,8 @@
 
     public OneTimeDeviceConfigListener(@NonNull String namespace, @NonNull String key,
             long timeoutMs) {
-        mNamespace = Preconditions.checkNotNull(namespace);
-        mKey = Preconditions.checkNotNull(key);
+        mNamespace = Objects.requireNonNull(namespace);
+        mKey = Objects.requireNonNull(key);
         mTimeoutMs = timeoutMs;
     }
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/RetryRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/RetryRule.java
index 32dedea..ca0e3e2 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/RetryRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/RetryRule.java
@@ -18,6 +18,8 @@
 
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
@@ -28,7 +30,17 @@
 public class RetryRule implements TestRule {
 
     private static final String TAG = "RetryRule";
+
+    /**
+     * An interface is used to clean up testing objects between the retries to make sure
+     * the testing environment is clean.
+     */
+    public interface RetryCleaner {
+        void clean();
+    }
+
     private final int mMaxAttempts;
+    private final RetryCleaner mCleaner;
 
     /**
      * Retries the underlying test when it catches a {@link RetryableException}.
@@ -38,10 +50,24 @@
      * @throws IllegalArgumentException if {@code retries} is less than {@code 0}.
      */
     public RetryRule(int retries) {
+        this(retries, null);
+    }
+
+    /**
+     * Retries the underlying test when it catches a {@link RetryableException}.
+     *
+     * @param retries number of retries. Use {@code 0} to disable rule.
+     * @param cleaner a {@link RetryCleaner} to clean up the objects generated by the testing
+     *               between retries
+     *
+     * @throws IllegalArgumentException if {@code retries} is less than {@code 0}.
+     */
+    public RetryRule(int retries, @Nullable RetryCleaner cleaner) {
         if (retries < 0) {
             throw new IllegalArgumentException("retries must be more than 0");
         }
         mMaxAttempts = retries + 1;
+        mCleaner = cleaner;
     }
 
     @Override
@@ -78,6 +104,9 @@
                                     + " to " + timeout.ms() + "ms");
                         }
                         caught = e;
+                        if (i != mMaxAttempts && mCleaner != null) {
+                            mCleaner.clean();
+                        }
                     }
                     Log.w(TAG, "Arrrr! " + name + " failed at attempt " + i + "/" + mMaxAttempts
                             + ": " + caught);
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsStateManager.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsStateManager.java
index bab06a6..c7be6b3 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsStateManager.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsStateManager.java
@@ -22,7 +22,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.google.common.base.Preconditions;
+import java.util.Objects;
 
 /**
  * Manages the state of a preference backed by {@link Settings}.
@@ -42,9 +42,9 @@
      */
     public SettingsStateManager(@NonNull Context context, @NonNull String namespace,
             @NonNull String key) {
-        mContext = Preconditions.checkNotNull(context);
-        mNamespace = Preconditions.checkNotNull(namespace);
-        mKey = Preconditions.checkNotNull(key);
+        mContext = Objects.requireNonNull(context);
+        mNamespace = Objects.requireNonNull(namespace);
+        mKey = Objects.requireNonNull(key);
     }
 
     @Override
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/StateChangerRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/StateChangerRule.java
index 4e59f13..3a0ceb0 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/StateChangerRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/StateChangerRule.java
@@ -19,8 +19,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.google.common.base.Preconditions;
-
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
@@ -47,7 +45,7 @@
      * @param value value to be set before the test is run.
      */
     public StateChangerRule(@NonNull StateManager<T> stateManager, @Nullable T value) {
-        mStateManager = Preconditions.checkNotNull(stateManager);
+        mStateManager = Objects.requireNonNull(stateManager);
         mValue = value;
     }
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/StateKeeperRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/StateKeeperRule.java
index ecc02a2..76e5fa7 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/StateKeeperRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/StateKeeperRule.java
@@ -18,8 +18,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.google.common.base.Preconditions;
-
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
@@ -43,7 +41,7 @@
      * @param stateManager abstraction used to mange the state.
      */
     public StateKeeperRule(@NonNull StateManager<T> stateManager) {
-        mStateManager = Preconditions.checkNotNull(stateManager);
+        mStateManager = Objects.requireNonNull(stateManager);
     }
 
     /**
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index c37fd33..91706c4 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.appsecurity
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts sts
 
 LOCAL_REQUIRED_MODULES := \
 	CtsCorruptApkTests_b71360999 \
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index 46ee46f..008eea4 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -23,6 +23,7 @@
 
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
+import android.platform.test.annotations.SecurityTest;
 
 import com.android.ddmlib.Log;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -224,6 +225,7 @@
      */
     @Test
     @AppModeFull(reason = "Only the platform can define permissions obtainable by instant applications")
+    @SecurityTest
     public void testPermissionDiffCert() throws Exception {
         Log.i(LOG_TAG, "installing app that attempts to use permission of another app");
         try {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 8ae80fc..ec3594e 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -614,6 +614,11 @@
         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Open", user);
         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Update", user);
         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Delete", user);
+
+        runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestWrite", user);
+        runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestTrash", user);
+        runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestFavorite", user);
+        runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestDelete", user);
     }
 
     @Test
diff --git a/hostsidetests/appsecurity/test-apps/Android.mk b/hostsidetests/appsecurity/test-apps/Android.mk
index f697a59..24249f2 100644
--- a/hostsidetests/appsecurity/test-apps/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
 
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/DeviceIdentifiers/src/android/appsecurity/cts/deviceids/DeviceIdentifierAppOpTest.java b/hostsidetests/appsecurity/test-apps/DeviceIdentifiers/src/android/appsecurity/cts/deviceids/DeviceIdentifierAppOpTest.java
index 1025c4d..71cd7d2 100644
--- a/hostsidetests/appsecurity/test-apps/DeviceIdentifiers/src/android/appsecurity/cts/deviceids/DeviceIdentifierAppOpTest.java
+++ b/hostsidetests/appsecurity/test-apps/DeviceIdentifiers/src/android/appsecurity/cts/deviceids/DeviceIdentifierAppOpTest.java
@@ -64,6 +64,9 @@
                     ShellIdentityUtils.invokeMethodWithShellPermissions(telephonyManager,
                             (tm) -> tm.getSimSerialNumber()),
                     telephonyManager.getSimSerialNumber());
+            assertEquals(String.format(DEVICE_ID_WITH_APPOP_ERROR_MESSAGE, "getNai"),
+                    ShellIdentityUtils.invokeMethodWithShellPermissions(telephonyManager,
+                            (tm) -> tm.getNai()), telephonyManager.getNai());
             assertEquals(String.format(DEVICE_ID_WITH_APPOP_ERROR_MESSAGE, "Build#getSerial"),
                     ShellIdentityUtils.invokeStaticMethodWithShellPermissions(Build::getSerial),
                     Build.getSerial());
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 30291a0..aafb94e 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
@@ -27,6 +27,7 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.app.PendingIntent;
 import android.app.RecoverableSecurityException;
 import android.content.ContentResolver;
 import android.content.ContentUris;
@@ -42,6 +43,7 @@
 import android.provider.MediaStore;
 import android.provider.MediaStore.MediaColumns;
 import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiSelector;
 
 import androidx.test.InstrumentationRegistry;
@@ -59,6 +61,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.concurrent.Callable;
 
@@ -103,9 +106,9 @@
     @Test
     public void testClearFiles() throws Exception {
         TEST_JPG.delete();
-        assertNull(MediaStore.scanFileFromShell(mContext, TEST_JPG));
+        assertNull(MediaStore.scanFile(mContentResolver, TEST_JPG));
         TEST_PDF.delete();
-        assertNull(MediaStore.scanFileFromShell(mContext, TEST_PDF));
+        assertNull(MediaStore.scanFile(mContentResolver, TEST_PDF));
     }
 
     private void doSandboxed(boolean sandboxed) throws Exception {
@@ -137,8 +140,8 @@
         assertTrue(TEST_JPG.exists());
         assertTrue(TEST_PDF.exists());
 
-        final Uri jpgUri = MediaStore.scanFileFromShell(mContext, TEST_JPG);
-        final Uri pdfUri = MediaStore.scanFileFromShell(mContext, TEST_PDF);
+        final Uri jpgUri = MediaStore.scanFile(mContentResolver, TEST_JPG);
+        final Uri pdfUri = MediaStore.scanFile(mContentResolver, TEST_PDF);
 
         final HashSet<Long> seen = new HashSet<>();
         try (Cursor c = mContentResolver.query(
@@ -375,7 +378,89 @@
         assertEquals(1, mContentResolver.delete(red, null, null));
     }
 
+    @Test
+    public void testMediaEscalation_RequestWrite() throws Exception {
+        doMediaEscalation_RequestWrite(MediaStorageTest::createAudio);
+        doMediaEscalation_RequestWrite(MediaStorageTest::createVideo);
+        doMediaEscalation_RequestWrite(MediaStorageTest::createImage);
+    }
+
+    private void doMediaEscalation_RequestWrite(Callable<Uri> create) throws Exception {
+        final Uri red = create.call();
+        clearMediaOwner(red, mUserId);
+
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(red, "w")) {
+            fail("Expected write access to be blocked");
+        } catch (RecoverableSecurityException expected) {
+        }
+
+        doEscalation(MediaStore.createWriteRequest(mContentResolver, Arrays.asList(red)));
+
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(red, "w")) {
+        }
+    }
+
+    @Test
+    public void testMediaEscalation_RequestTrash() throws Exception {
+        doMediaEscalation_RequestTrash(MediaStorageTest::createAudio);
+        doMediaEscalation_RequestTrash(MediaStorageTest::createVideo);
+        doMediaEscalation_RequestTrash(MediaStorageTest::createImage);
+    }
+
+    private void doMediaEscalation_RequestTrash(Callable<Uri> create) throws Exception {
+        final Uri red = create.call();
+        clearMediaOwner(red, mUserId);
+
+        assertEquals("0", queryForSingleColumn(red, MediaColumns.IS_TRASHED));
+        doEscalation(MediaStore.createTrashRequest(mContentResolver, Arrays.asList(red), true));
+        assertEquals("1", queryForSingleColumn(red, MediaColumns.IS_TRASHED));
+        doEscalation(MediaStore.createTrashRequest(mContentResolver, Arrays.asList(red), false));
+        assertEquals("0", queryForSingleColumn(red, MediaColumns.IS_TRASHED));
+    }
+
+    @Test
+    public void testMediaEscalation_RequestFavorite() throws Exception {
+        doMediaEscalation_RequestFavorite(MediaStorageTest::createAudio);
+        doMediaEscalation_RequestFavorite(MediaStorageTest::createVideo);
+        doMediaEscalation_RequestFavorite(MediaStorageTest::createImage);
+    }
+
+    private void doMediaEscalation_RequestFavorite(Callable<Uri> create) throws Exception {
+        final Uri red = create.call();
+        clearMediaOwner(red, mUserId);
+
+        assertEquals("0", queryForSingleColumn(red, MediaColumns.IS_FAVORITE));
+        doEscalation(MediaStore.createFavoriteRequest(mContentResolver, Arrays.asList(red), true));
+        assertEquals("1", queryForSingleColumn(red, MediaColumns.IS_FAVORITE));
+        doEscalation(MediaStore.createFavoriteRequest(mContentResolver, Arrays.asList(red), false));
+        assertEquals("0", queryForSingleColumn(red, MediaColumns.IS_FAVORITE));
+    }
+
+    @Test
+    public void testMediaEscalation_RequestDelete() throws Exception {
+        doMediaEscalation_RequestDelete(MediaStorageTest::createAudio);
+        doMediaEscalation_RequestDelete(MediaStorageTest::createVideo);
+        doMediaEscalation_RequestDelete(MediaStorageTest::createImage);
+    }
+
+    private void doMediaEscalation_RequestDelete(Callable<Uri> create) throws Exception {
+        final Uri red = create.call();
+        clearMediaOwner(red, mUserId);
+
+        try (Cursor c = mContentResolver.query(red, null, null, null)) {
+            assertEquals(1, c.getCount());
+        }
+        doEscalation(MediaStore.createDeleteRequest(mContentResolver, Arrays.asList(red)));
+        try (Cursor c = mContentResolver.query(red, null, null, null)) {
+            assertEquals(0, c.getCount());
+        }
+    }
+
     private void doEscalation(RecoverableSecurityException exception) throws Exception {
+        doEscalation(exception.getUserAction().getActionIntent());
+    }
+
+    private void doEscalation(PendingIntent pi) throws Exception {
         // Try launching the action to grant ourselves access
         final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
         final Intent intent = new Intent(inst.getContext(), GetResultActivity.class);
@@ -389,12 +474,17 @@
         final GetResultActivity activity = (GetResultActivity) inst.startActivitySync(intent);
         device.waitForIdle();
         activity.clearResult();
-        activity.startIntentSenderForResult(
-                exception.getUserAction().getActionIntent().getIntentSender(),
-                42, null, 0, 0, 0);
+        activity.startIntentSenderForResult(pi.getIntentSender(), 42, null, 0, 0, 0);
 
         device.waitForIdle();
-        device.findObject(new UiSelector().textMatches("(?i:Allow)")).click();
+
+        // Some dialogs may have granted access automatically, so we're willing
+        // to keep rolling forward if we can't find our grant button
+        final UiSelector grant = new UiSelector()
+                .textMatches("(Allow|Change|Move to trash|Move out of trash|Delete)");
+        if (new UiObject(grant).waitForExists(2_000)) {
+            device.findObject(grant).click();
+        }
 
         // Verify that we now have access
         final GetResultActivity.Result res = activity.getResult();
@@ -446,6 +536,16 @@
         }
     }
 
+    private static String queryForSingleColumn(Uri uri, String column) throws Exception {
+        final ContentResolver resolver = InstrumentationRegistry.getTargetContext()
+                .getContentResolver();
+        try (Cursor c = resolver.query(uri, new String[] { column }, null, null)) {
+            assertEquals(c.getCount(), 1);
+            assertTrue(c.moveToFirst());
+            return c.getString(0);
+        }
+    }
+
     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:",
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
index 64a8e7c..4c79dca 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
@@ -23,6 +23,7 @@
         "cts",
         "vts",
         "general-tests",
+        "sts",
     ],
     // sign this app with a different cert than CtsUsePermissionDiffCert
     certificate: ":cts-testkey1",
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp
index 54161d6..76203e9 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp
@@ -23,6 +23,7 @@
         "cts",
         "vts",
         "general-tests",
+        "sts",
     ],
     // sign this app with a different cert than CtsUsePermissionDiffCert
     certificate: ":cts-testkey1",
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index d116a08..8b5630c 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -449,7 +449,7 @@
                     waitForIdle();
                 }
 
-                final boolean wasGranted = isTv() ? false : !(waitFindObject(byText(R.string.Deny)).isChecked() || waitFindObject(byText(R.string.Ask)).isChecked());
+                final boolean wasGranted = isTv() ? false : !(waitFindObject(byText(R.string.Deny)).isChecked() || (!legacyApp && waitFindObject(byText(R.string.Ask)).isChecked()));
                 boolean alreadyChecked = false;
                 if (isTv()) {
                     waitFindObject(By.text(permissionLabel)).click();
@@ -460,7 +460,12 @@
                         object.click();
                     }
                 } else if (state == STATE_DENIED){
-                    UiObject2 object = waitFindObject(byText(R.string.Ask));
+                    UiObject2 object;
+                    if (legacyApp) {
+                        object = waitFindObject(byText(R.string.Deny));
+                    } else {
+                        object = waitFindObject(byText(R.string.Ask));
+                    }
                     alreadyChecked = object.isChecked();
                     if (!alreadyChecked) {
                         object.click();
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp
index b11c4cc..cbedea9 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp
@@ -29,6 +29,7 @@
         "cts",
         "vts",
         "general-tests",
+        "sts",
     ],
     // sign this app with a different cert than CtsPermissionDeclareApp
     certificate: ":cts-testkey2",
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index dd2d9ff..7d96581 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -261,7 +261,7 @@
         final List<File> paths = getAllPackageSpecificPathsExceptMedia(getContext());
 
         for (File path : paths) {
-            MediaStore.scanFile(getContext(), path);
+            MediaStore.scanFile(getContext().getContentResolver(), path);
         }
 
         // Require that .nomedia was created somewhere above each dir
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java
index 95972a2..05335a1 100644
--- a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java
@@ -24,23 +24,6 @@
 import com.android.cts.comp.AdminReceiver;
 
 public class UserRestrictionTest extends AndroidTestCase {
-
-    public void testAddDisallowAddManagedProfileRestriction() {
-        setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true);
-    }
-
-    public void testClearDisallowAddManagedProfileRestriction() {
-        setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false);
-    }
-
-    public void testAddDisallowRemoveManagedProfileRestriction() {
-        setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true);
-    }
-
-    public void testClearDisallowRemoveManagedProfileRestriction() {
-        setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false);
-    }
-
     public void testAddDisallowRemoveUserRestriction() {
         setUserRestriction(UserManager.DISALLOW_REMOVE_USER, true);
     }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DeviceIdentifiersTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DeviceIdentifiersTest.java
index 2e5f4b2..ebaf592 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DeviceIdentifiersTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DeviceIdentifiersTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.cts.deviceandprofileowner;
 
+import static org.testng.Assert.assertThrows;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
@@ -61,6 +63,9 @@
                     ShellIdentityUtils.invokeMethodWithShellPermissions(telephonyManager,
                             (tm) -> tm.getSimSerialNumber()),
                     telephonyManager.getSimSerialNumber());
+            assertEquals(String.format(DEVICE_ID_WITH_PERMISSION_ERROR_MESSAGE, "getNai"),
+                    ShellIdentityUtils.invokeMethodWithShellPermissions(telephonyManager,
+                            (tm) -> tm.getNai()), telephonyManager.getNai());
             assertEquals(String.format(DEVICE_ID_WITH_PERMISSION_ERROR_MESSAGE, "Build#getSerial"),
                     ShellIdentityUtils.invokeStaticMethodWithShellPermissions(Build::getSerial),
                     Build.getSerial());
@@ -78,64 +83,22 @@
         // Allow the APIs to also return null if the telephony feature is not supported.
         boolean hasTelephonyFeature =
                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-        try {
-            String deviceId = telephonyManager.getDeviceId();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getDeviceId"));
-            } else {
-                assertEquals(null, deviceId);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String imei = telephonyManager.getImei();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getImei"));
-            } else {
-                assertEquals(null, imei);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String meid = telephonyManager.getMeid();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getMeid"));
-            } else {
-                assertEquals(null, meid);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String subscriberId = telephonyManager.getSubscriberId();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSubscriberId"));
-            } else {
-                assertEquals(null, subscriberId);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String simSerialNumber = telephonyManager.getSimSerialNumber();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSimSerialNumber"));
-            } else {
-                assertEquals(null, simSerialNumber);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String serial = Build.getSerial();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "Build#getSerial"));
-            } else {
-              assertEquals(null, serial);
-            }
-        } catch (SecurityException expected) {
+        if (hasTelephonyFeature) {
+            assertThrows(SecurityException.class, telephonyManager::getDeviceId);
+            assertThrows(SecurityException.class, telephonyManager::getImei);
+            assertThrows(SecurityException.class, telephonyManager::getMeid);
+            assertThrows(SecurityException.class, telephonyManager::getSubscriberId);
+            assertThrows(SecurityException.class, telephonyManager::getSimSerialNumber);
+            assertThrows(SecurityException.class, telephonyManager::getNai);
+            assertThrows(SecurityException.class, Build::getSerial);
+        } else {
+            assertNull(telephonyManager.getDeviceId());
+            assertNull(telephonyManager.getImei());
+            assertNull(telephonyManager.getMeid());
+            assertNull(telephonyManager.getSubscriberId());
+            assertNull(telephonyManager.getSimSerialNumber());
+            assertNull(telephonyManager.getNai());
+            assertNull(Build.getSerial());
         }
     }
 }
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 302523b..0b6ce32 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
@@ -17,6 +17,7 @@
 
 import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_INDIVIDUAL_ATTESTATION;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
 import static android.keystore.cts.CertificateUtils.createCertificate;
@@ -657,7 +658,103 @@
         }
     }
 
-    public void testCanSetKeyPairCert() throws Exception {
+    public void testUniqueDeviceAttestationUsingDifferentAttestationCert() throws Exception {
+        // This test is only applicable in modes where Device ID attestation can be performed
+        // _and_ the device has StrongBox, which is provisioned with individual attestation
+        // certificates.
+        // The functionality tested should equally work for when the Profile Owner can perform
+        // Device ID attestation, but since the underlying StrongBox implementation cannot
+        // differentiate between PO and DO modes, for simplicity, it is only tested in DO mode.
+        if (!isDeviceOwner() || !hasStrongBox() || !isUniqueDeviceAttestationSupported()) {
+            return;
+        }
+        final String no_id_alias = "com.android.test.key_attested";
+        final String dev_unique_alias = "com.android.test.individual_dev_attested";
+
+        byte[] attestationChallenge = new byte[] {0x01, 0x02, 0x03};
+        try {
+            KeyGenParameterSpec specKeyAttOnly = new KeyGenParameterSpec.Builder(
+                    no_id_alias,
+                    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+                    .setDigests(KeyProperties.DIGEST_SHA256)
+                    .setAttestationChallenge(attestationChallenge)
+                    .setIsStrongBoxBacked(true)
+                    .build();
+
+            AttestedKeyPair attestedKeyPair = mDevicePolicyManager.generateKeyPair(
+                    getWho(), KeyProperties.KEY_ALGORITHM_EC, specKeyAttOnly,
+                    0 /* device id attestation flags */);
+            assertWithMessage(
+                    String.format("Failed generating a key with attestation in StrongBox."))
+                    .that(attestedKeyPair)
+                    .isNotNull();
+
+            KeyGenParameterSpec specIndividualAtt = new KeyGenParameterSpec.Builder(
+                    dev_unique_alias,
+                    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+                    .setDigests(KeyProperties.DIGEST_SHA256)
+                    .setAttestationChallenge(attestationChallenge)
+                    .setIsStrongBoxBacked(true)
+                    .build();
+
+            AttestedKeyPair individuallyAttestedPair = mDevicePolicyManager.generateKeyPair(
+                    getWho(), KeyProperties.KEY_ALGORITHM_EC, specIndividualAtt,
+                    ID_TYPE_INDIVIDUAL_ATTESTATION /* device id attestation flags */);
+            assertWithMessage(
+                    String.format("Failed generating a key for unique attestation in StrongBox."))
+                    .that(individuallyAttestedPair)
+                    .isNotNull();
+
+            X509Certificate keyAttestationIntermediate = (X509Certificate)
+                    attestedKeyPair.getAttestationRecord().get(1);
+            X509Certificate devUniqueAttestationIntermediate = (X509Certificate)
+                    individuallyAttestedPair.getAttestationRecord().get(1);
+            assertWithMessage("Device unique attestation intermediate certificate"
+                    + " should be different to the key attestation certificate.")
+                    .that(devUniqueAttestationIntermediate.getEncoded())
+                    .isNotEqualTo(keyAttestationIntermediate.getEncoded());
+        } finally {
+            mDevicePolicyManager.removeKeyPair(getWho(), no_id_alias);
+            mDevicePolicyManager.removeKeyPair(getWho(), dev_unique_alias);
+        }
+    }
+
+    public void testUniqueDeviceAttestationFailsWhenUnsupported() {
+        if (!isDeviceOwner() || !hasStrongBox()) {
+            return;
+        }
+
+        if (isUniqueDeviceAttestationSupported()) {
+            // testUniqueDeviceAttestationUsingDifferentAttestationCert is the positive test case.
+            return;
+        }
+
+        byte[] attestationChallenge = new byte[] {0x01, 0x02, 0x03};
+        final String someAlias = "com.android.test.should_not_exist";
+        try {
+            KeyGenParameterSpec specIndividualAtt = new KeyGenParameterSpec.Builder(
+                    someAlias,
+                    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+                    .setDigests(KeyProperties.DIGEST_SHA256)
+                    .setAttestationChallenge(attestationChallenge)
+                    .setIsStrongBoxBacked(true)
+                    .build();
+
+            AttestedKeyPair individuallyAttestedPair = mDevicePolicyManager.generateKeyPair(
+                    getWho(), KeyProperties.KEY_ALGORITHM_EC, specIndividualAtt,
+                    ID_TYPE_INDIVIDUAL_ATTESTATION /* device id attestation flags */);
+            assertWithMessage(
+                    String.format("When unique attestation is not supported, key generation "
+                            + "should fail."))
+                    .that(individuallyAttestedPair)
+                    .isNull();
+        } finally {
+            mDevicePolicyManager.removeKeyPair(getWho(), someAlias);
+        }
+    }
+
+
+        public void testCanSetKeyPairCert() throws Exception {
         final String alias = "com.android.test.set-ec-1";
         try {
             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
@@ -798,4 +895,8 @@
         return mActivity.getPackageManager()
             .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE);
     }
+
+    boolean isUniqueDeviceAttestationSupported() {
+        return mDevicePolicyManager.isUniqueDeviceAttestationSupported();
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java
index 869b861..2b36cde 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java
@@ -22,19 +22,22 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
 import android.test.InstrumentationTestCase;
 
 public class OrgOwnedProfileOwnerParentTest extends InstrumentationTestCase {
 
     protected Context mContext;
     private DevicePolicyManager mParentDevicePolicyManager;
+    private DevicePolicyManager mDevicePolicyManager;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getContext();
 
-        DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager)
+        mDevicePolicyManager = (DevicePolicyManager)
                 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mParentDevicePolicyManager =
                 mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
@@ -62,4 +65,22 @@
         // TODO: (145604715) test camera is actually disabled
     }
 
-}
+    public void testAddGetAndClearUserRestriction_onParent() {
+        mParentDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                UserManager.DISALLOW_CONFIG_DATE_TIME);
+
+        Bundle restrictions = mParentDevicePolicyManager.getUserRestrictions(
+                ADMIN_RECEIVER_COMPONENT);
+        assertThat(restrictions.get(UserManager.DISALLOW_CONFIG_DATE_TIME)).isNotNull();
+
+        restrictions = mDevicePolicyManager.getUserRestrictions(ADMIN_RECEIVER_COMPONENT);
+        assertThat(restrictions.get(UserManager.DISALLOW_CONFIG_DATE_TIME)).isNull();
+
+        mParentDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                UserManager.DISALLOW_CONFIG_DATE_TIME);
+
+        restrictions = mParentDevicePolicyManager.getUserRestrictions(ADMIN_RECEIVER_COMPONENT);
+        assertThat(restrictions.get(UserManager.DISALLOW_CONFIG_DATE_TIME)).isNull();
+    }
+
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/TimeManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/TimeManagementTest.java
new file mode 100644
index 0000000..771b13b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/TimeManagementTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class TimeManagementTest extends BaseDeviceAdminTest {
+
+    public void testSetAutoTimeZone() {
+        mDevicePolicyManager.setAutoTimeZone(ADMIN_RECEIVER_COMPONENT, true);
+
+        boolean autoTimeZone = mDevicePolicyManager.getAutoTimeZone(ADMIN_RECEIVER_COMPONENT);
+        assertThat(autoTimeZone).isTrue();
+
+        mDevicePolicyManager.setAutoTimeZone(ADMIN_RECEIVER_COMPONENT, false);
+
+        autoTimeZone = mDevicePolicyManager.getAutoTimeZone(ADMIN_RECEIVER_COMPONENT);
+        assertThat(autoTimeZone).isFalse();
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java
new file mode 100644
index 0000000..b0b398e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.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 static com.android.cts.deviceandprofileowner.BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.UserManager;
+import android.test.InstrumentationTestCase;
+
+public class UserRestrictionsParentTest extends InstrumentationTestCase {
+
+    protected Context mContext;
+    private DevicePolicyManager mDevicePolicyManager;
+    private UserManager mUserManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getContext();
+
+        mDevicePolicyManager = (DevicePolicyManager)
+                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        assertNotNull(mDevicePolicyManager);
+
+        mUserManager = mContext.getSystemService(UserManager.class);
+        assertNotNull(mUserManager);
+    }
+
+    public void testAddUserRestriction_onParent() {
+        DevicePolicyManager parentDevicePolicyManager =
+                mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
+        assertNotNull(parentDevicePolicyManager);
+
+        parentDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                UserManager.DISALLOW_CONFIG_DATE_TIME);
+    }
+
+    public void testHasUserRestriction() {
+        assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME)).isTrue();
+    }
+
+    public void testUserRestrictionAreNotPersisted() {
+        assertThat(
+                mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME)).isFalse();
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
index 5569653..41c162e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
@@ -42,14 +42,12 @@
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_CREDENTIALS,
             UserManager.DISALLOW_REMOVE_USER,
-            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
             UserManager.DISALLOW_DEBUGGING_FEATURES,
             UserManager.DISALLOW_CONFIG_VPN,
             UserManager.DISALLOW_CONFIG_TETHERING,
             UserManager.DISALLOW_NETWORK_RESET,
             UserManager.DISALLOW_FACTORY_RESET,
             UserManager.DISALLOW_ADD_USER,
-            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
             UserManager.ENSURE_VERIFY_APPS,
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
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 6c33dba..2b6dca6 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
@@ -30,14 +30,12 @@
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_CREDENTIALS,
             UserManager.DISALLOW_REMOVE_USER,
-            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
             // UserManager.DISALLOW_DEBUGGING_FEATURES, // Need for CTS
             UserManager.DISALLOW_CONFIG_VPN,
             UserManager.DISALLOW_CONFIG_TETHERING,
             UserManager.DISALLOW_NETWORK_RESET,
             UserManager.DISALLOW_FACTORY_RESET,
             UserManager.DISALLOW_ADD_USER,
-            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
             // UserManager.ENSURE_VERIFY_APPS, // Has unrecoverable side effects.
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -68,7 +66,7 @@
     };
 
     public static final String[] DEFAULT_ENABLED = new String[] {
-            UserManager.DISALLOW_ADD_MANAGED_PROFILE
+            // No restrictions set for DO by default.
     };
 
     @Override
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java
index 3c53de9..e5ea597 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.cts.deviceowner;
 
+import static org.testng.Assert.assertThrows;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
@@ -30,9 +32,6 @@
     private static final String DEVICE_ID_WITH_PERMISSION_ERROR_MESSAGE =
             "An unexpected value was received by the device owner with the READ_PHONE_STATE "
                     + "permission when invoking %s";
-    private static final String NO_SECURITY_EXCEPTION_ERROR_MESSAGE =
-            "A device owner that does not have the READ_PHONE_STATE permission must receive a "
-                    + "SecurityException when invoking %s";
 
     public void testDeviceOwnerCanGetDeviceIdentifiersWithPermission() throws Exception {
         // The device owner with the READ_PHONE_STATE permission should have access to all device
@@ -59,6 +58,10 @@
                     ShellIdentityUtils.invokeMethodWithShellPermissions(telephonyManager,
                             (tm) -> tm.getSimSerialNumber()),
                     telephonyManager.getSimSerialNumber());
+            assertEquals(
+                    String.format(DEVICE_ID_WITH_PERMISSION_ERROR_MESSAGE, "getNai"),
+                    ShellIdentityUtils.invokeMethodWithShellPermissions(telephonyManager,
+                            (tm) -> tm.getNai()), telephonyManager.getNai());
             assertEquals(String.format(DEVICE_ID_WITH_PERMISSION_ERROR_MESSAGE, "Build#getSerial"),
                     ShellIdentityUtils.invokeStaticMethodWithShellPermissions(Build::getSerial),
                     Build.getSerial());
@@ -76,64 +79,22 @@
         // Allow the APIs to also return null if the telephony feature is not supported.
         boolean hasTelephonyFeature =
                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-        try {
-            String deviceId = telephonyManager.getDeviceId();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getDeviceId"));
-            } else {
-                assertEquals(null, deviceId);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String imei = telephonyManager.getImei();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getImei"));
-            } else {
-                assertEquals(null, imei);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String meid = telephonyManager.getMeid();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getMeid"));
-            } else {
-                assertEquals(null, meid);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String subscriberId = telephonyManager.getSubscriberId();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSubscriberId"));
-            } else {
-                assertEquals(null, subscriberId);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String simSerialNumber = telephonyManager.getSimSerialNumber();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSimSerialNumber"));
-            } else {
-                assertEquals(null, simSerialNumber);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String serial = Build.getSerial();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "Build#getSerial"));
-            } else {
-              assertEquals(null, serial);
-            }
-        } catch (SecurityException expected) {
+        if (hasTelephonyFeature) {
+            assertThrows(SecurityException.class, telephonyManager::getDeviceId);
+            assertThrows(SecurityException.class, telephonyManager::getImei);
+            assertThrows(SecurityException.class, telephonyManager::getMeid);
+            assertThrows(SecurityException.class, telephonyManager::getSubscriberId);
+            assertThrows(SecurityException.class, telephonyManager::getSimSerialNumber);
+            assertThrows(SecurityException.class, telephonyManager::getNai);
+            assertThrows(SecurityException.class, Build::getSerial);
+        } else {
+            assertNull(telephonyManager.getDeviceId());
+            assertNull(telephonyManager.getImei());
+            assertNull(telephonyManager.getMeid());
+            assertNull(telephonyManager.getSubscriberId());
+            assertNull(telephonyManager.getSimSerialNumber());
+            assertNull(telephonyManager.getNai());
+            assertNull(Build.getSerial());
         }
     }
 }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileTest.java
new file mode 100644
index 0000000..795e34f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.managedprofile;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+
+import java.util.Collections;
+import java.util.Set;
+
+/** App-side tests for interacting across profiles. */
+public class CrossProfileTest extends BaseManagedProfileTest {
+    private static final ComponentName NON_ADMIN_RECEIVER =
+            new ComponentName(
+                    NonAdminReceiver.class.getPackage().getName(),
+                    NonAdminReceiver.class.getName());
+
+    private static final Set<String> TEST_CROSS_PROFILE_PACKAGES =
+            Collections.singleton("test.package.name");
+
+    public void testSetCrossProfilePackages_notProfileOwner_throwsSecurityException() {
+        try {
+            mDevicePolicyManager.setCrossProfilePackages(
+                    NON_ADMIN_RECEIVER, TEST_CROSS_PROFILE_PACKAGES);
+            fail("SecurityException excepted.");
+        } catch (SecurityException ignored) {}
+    }
+
+    public void testGetCrossProfilePackages_notProfileOwner_throwsSecurityException() {
+        try {
+            mDevicePolicyManager.getCrossProfilePackages(NON_ADMIN_RECEIVER);
+            fail("SecurityException expected.");
+        } catch (SecurityException ignored) {}
+    }
+
+    public void testGetCrossProfilePackages_notSet_returnsEmpty() {
+        assertThat(mDevicePolicyManager.getCrossProfilePackages(ADMIN_RECEIVER_COMPONENT))
+                .isEmpty();
+    }
+
+    public void testGetCrossProfilePackages_whenSet_returnsEqual() {
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, TEST_CROSS_PROFILE_PACKAGES);
+        assertThat(mDevicePolicyManager.getCrossProfilePackages(ADMIN_RECEIVER_COMPONENT))
+                .isEqualTo(TEST_CROSS_PROFILE_PACKAGES);
+    }
+
+    public void testGetCrossProfilePackages_whenSetTwice_returnsLatestNotConcatenated() {
+        final Set<String> packages1 = Collections.singleton("test.package.name.1");
+        final Set<String> packages2 = Collections.singleton("test.package.name.2");
+
+        mDevicePolicyManager.setCrossProfilePackages(ADMIN_RECEIVER_COMPONENT, packages1);
+        mDevicePolicyManager.setCrossProfilePackages(ADMIN_RECEIVER_COMPONENT, packages2);
+
+        assertThat(mDevicePolicyManager.getCrossProfilePackages(ADMIN_RECEIVER_COMPONENT))
+                .isEqualTo(packages2);
+    }
+
+    private static class NonAdminReceiver extends DeviceAdminReceiver {}
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java
index edfd1bb..68c4d3c 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.cts.managedprofile;
 
+import static org.testng.Assert.assertThrows;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
@@ -24,9 +26,6 @@
  * Verifies a profile owner on a personal device cannot access device identifiers.
  */
 public class DeviceIdentifiersTest extends BaseManagedProfileTest {
-    private static final String NO_SECURITY_EXCEPTION_ERROR_MESSAGE =
-            "A profile owner that does not have the READ_PHONE_STATE permission must receive a "
-                    + "SecurityException when invoking %s";
 
     public void testProfileOwnerOnPersonalDeviceCannotGetDeviceIdentifiers() throws Exception {
         // The profile owner with the READ_PHONE_STATE permission should still receive a
@@ -37,64 +36,22 @@
         // Allow the APIs to also return null if the telephony feature is not supported.
         boolean hasTelephonyFeature =
                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-        try {
-            String deviceId = telephonyManager.getDeviceId();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getDeviceId"));
-            } else {
-                assertEquals(null, deviceId);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String imei = telephonyManager.getImei();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getImei"));
-            } else {
-                assertEquals(null, imei);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String meid = telephonyManager.getMeid();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getMeid"));
-            } else {
-                assertEquals(null, meid);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String subscriberId = telephonyManager.getSubscriberId();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSubscriberId"));
-            } else {
-                assertEquals(null, subscriberId);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String simSerialNumber = telephonyManager.getSimSerialNumber();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSimSerialNumber"));
-            } else {
-                assertEquals(null, simSerialNumber);
-            }
-        } catch (SecurityException expected) {
-        }
-
-        try {
-            String serial = Build.getSerial();
-            if (hasTelephonyFeature) {
-                fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "Build#getSerial"));
-            } else {
-              assertEquals(null, serial);
-            }
-        } catch (SecurityException expected) {
+        if (hasTelephonyFeature) {
+            assertThrows(SecurityException.class, telephonyManager::getDeviceId);
+            assertThrows(SecurityException.class, telephonyManager::getImei);
+            assertThrows(SecurityException.class, telephonyManager::getMeid);
+            assertThrows(SecurityException.class, telephonyManager::getSubscriberId);
+            assertThrows(SecurityException.class, telephonyManager::getSimSerialNumber);
+            assertThrows(SecurityException.class, telephonyManager::getNai);
+            assertThrows(SecurityException.class, Build::getSerial);
+        } else {
+            assertNull(telephonyManager.getDeviceId());
+            assertNull(telephonyManager.getImei());
+            assertNull(telephonyManager.getMeid());
+            assertNull(telephonyManager.getSubscriberId());
+            assertNull(telephonyManager.getSimSerialNumber());
+            assertNull(telephonyManager.getNai());
+            assertNull(Build.getSerial());
         }
     }
 }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
index aa221cc..a901d73 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.managedprofile;
 
+import static org.testng.Assert.assertThrows;
+
 import android.app.admin.DevicePolicyManager;
 import android.util.Log;
 
@@ -82,6 +84,9 @@
             .add("setRequiredStrongAuthTimeout")
             .add("isDeviceIdAttestationSupported")
             .add("isUniqueDeviceAttestationSupported")
+            .add("wipeData")
+            .add("getAutoTime")
+            .add("setAutoTime")
             .build();
 
     private static final String LOG_TAG = "ParentProfileTest";
@@ -146,4 +151,18 @@
             assertTrue(name + " is not found in the API list", allNames.contains(name));
         }
     }
+
+    public void testCannotWipeParentProfile() {
+        assertThrows(SecurityException.class,
+                () -> mParentDevicePolicyManager.wipeData(0));
+    }
+
+    public void testCannotCallAutoTimeMethodsOnParentProfile() {
+        assertThrows(SecurityException.class,
+                () -> mParentDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, true));
+
+        assertThrows(SecurityException.class,
+                () -> mParentDevicePolicyManager.getAutoTime(ADMIN_RECEIVER_COMPONENT));
+    }
+
 }
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java
index 6aedd1b..bead632 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java
@@ -146,16 +146,6 @@
     }
 
     @Test
-    public void testClearDisallowAddManagedProfileRestriction() {
-        setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false);
-    }
-
-    @Test
-    public void testAddDisallowAddManagedProfileRestriction() {
-        setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true);
-    }
-
-    @Test
     public void testSetAffiliationId1() {
         setAffiliationId("id.number.1");
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
index d12dbb3..89788c7 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
@@ -182,15 +182,7 @@
 
     protected int setupManagedProfileOnDeviceOwner(String apkName, String adminReceiverClassName)
             throws Exception {
-        // Temporary disable the DISALLOW_ADD_MANAGED_PROFILE, so that we can create profile
-        // using adb command.
-        clearDisallowAddManagedProfileRestriction();
-        try {
-            return setupManagedProfile(apkName, adminReceiverClassName);
-        } finally {
-            // Adding back DISALLOW_ADD_MANAGED_PROFILE.
-            addDisallowAddManagedProfileRestriction();
-        }
+        return setupManagedProfile(apkName, adminReceiverClassName);
     }
 
     protected int setupManagedProfile(String apkName, String adminReceiverClassName)
@@ -207,28 +199,6 @@
         return userId;
     }
 
-    /**
-     * Clear {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
-     */
-    private void clearDisallowAddManagedProfileRestriction() throws Exception {
-        runDeviceTestsAsUser(
-                TRANSFER_OWNER_OUTGOING_PKG,
-                mOutgoingTestClassName,
-                "testClearDisallowAddManagedProfileRestriction",
-                mPrimaryUserId);
-    }
-
-    /**
-     * Add {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
-     */
-    private void addDisallowAddManagedProfileRestriction() throws Exception {
-        runDeviceTestsAsUser(
-                TRANSFER_OWNER_OUTGOING_PKG,
-                mOutgoingTestClassName,
-                "testAddDisallowAddManagedProfileRestriction",
-                mPrimaryUserId);
-    }
-
     @Test
     public void testTargetDeviceAdminServiceBound() throws Exception {
         if (!mHasFeature) {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 191ef17..9e605d6 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -1941,6 +1941,23 @@
     }
 
     @Test
+    public void testSetAutoTimeZone() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        assertMetricsLogged(getDevice(), () -> {
+                    executeDeviceTestMethod(".TimeManagementTest", "testSetAutoTimeZone");
+                }, new DevicePolicyEventWrapper.Builder(EventId.SET_AUTO_TIME_ZONE_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setBoolean(true)
+                        .build(),
+                new DevicePolicyEventWrapper.Builder(EventId.SET_AUTO_TIME_ZONE_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setBoolean(false)
+                        .build());
+    }
+
+    @Test
     public void testEnableSystemAppLogged() throws Exception {
         if (!mHasFeature || !isStatsdEnabled(getDevice())) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
index 33ec4fa..a6b791b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
@@ -31,6 +31,7 @@
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper.Builder;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.List;
@@ -239,19 +240,6 @@
         verifyBindDeviceAdminServiceAsUser(secondaryUserId);
     }
 
-    @Test
-    public void testCannotRemoveProfileIfRestrictionSet() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-        int profileUserId = setupManagedProfile(COMP_DPC_APK2, COMP_DPC_PKG2, COMP_DPC_ADMIN2);
-        addDisallowRemoveManagedProfileRestriction();
-        assertFalse(getDevice().removeUser(profileUserId));
-
-        clearDisallowRemoveManagedProfileRestriction();
-        assertTrue(getDevice().removeUser(profileUserId));
-    }
-
     @FlakyTest(bugId = 141161038)
     @Test
     public void testCannotRemoveUserIfRestrictionSet() throws Exception {
@@ -285,7 +273,6 @@
         }
         int profileUserId = setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
         addDisallowRemoveUserRestriction();
-        addDisallowRemoveManagedProfileRestriction();
 
         // The DO should be allowed to remove the managed profile, even though disallow remove user
         // and disallow remove managed profile restrictions are set.
@@ -297,7 +284,10 @@
         assertUserGetsRemoved(profileUserId);
     }
 
+    //TODO(b/138709492) Re-enable once restriction on creating a work profile when there's
+    // a device owner is on by default.
     @Test
+    @Ignore
     public void testCannotAddProfileIfRestrictionSet() throws Exception {
         if (!mHasFeature) {
             return;
@@ -307,6 +297,7 @@
     }
 
     /**
+     * TODO(b/138709492): Remove this test as a part of the COMP deprecation.
      * Both device owner and profile are the same package ({@link #COMP_DPC_PKG}).
      */
     @Test
@@ -315,27 +306,18 @@
             return;
         }
         installAppAsUser(COMP_DPC_APK2, mPrimaryUserId);
-        // By default, disallow add managed profile is set, so provisioning a managed profile is
-        // not allowed for DPCs other than the device owner.
-        assertProvisionManagedProfileNotAllowed(COMP_DPC_PKG2);
-        // But the device owner can still provision a managed profile because it owns the
-        // restriction.
+        // Disallowing adding managed profile is no longer set by default, so every DPC can
+        // provision a work profile.
+        assertProvisionManagedProfileAllowed(COMP_DPC_PKG2);
+        // Including the device owner, which can still provision a managed profile.
         assertProvisionManagedProfileAllowed(COMP_DPC_PKG);
 
         setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
 
-        clearDisallowAddManagedProfileRestriction();
         // We've created a managed profile, but it's still possible to delete it to create a new
         // one.
         assertProvisionManagedProfileAllowed(COMP_DPC_PKG2);
         assertProvisionManagedProfileAllowed(COMP_DPC_PKG);
-
-        addDisallowRemoveManagedProfileRestriction();
-        // Now we can't delete the managed profile any more to create a new one.
-        assertProvisionManagedProfileNotAllowed(COMP_DPC_PKG2);
-        // But if it is initiated by the device owner, it is still possible, because the device
-        // owner itself has set the restriction
-        assertProvisionManagedProfileAllowed(COMP_DPC_PKG);
     }
 
     @Test
@@ -344,7 +326,6 @@
             return;
         }
         int profileUserId = setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
-        addDisallowRemoveManagedProfileRestriction();
         // The PO of the managed profile should be allowed to delete the managed profile, even
         // though the disallow remove profile restriction is set.
         runDeviceTestsAsUser(
@@ -361,7 +342,6 @@
             return;
         }
         int profileUserId = setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
-        addDisallowRemoveManagedProfileRestriction();
         assertMetricsLogged(getDevice(), () -> {
             runDeviceTestsAsUser(COMP_DPC_PKG, MANAGEMENT_TEST, "testWipeData", profileUserId);
         }, WIPE_DATA_WITH_REASON_DEVICE_POLICY_EVENT);
@@ -624,24 +604,16 @@
     /** Returns the user id of the newly created managed profile */
     private int setupManagedProfile(String apkName, String packageName,
             String adminReceiverClassName) throws Exception {
-        // Temporary disable the DISALLOW_ADD_MANAGED_PROFILE, so that we can create profile
-        // using adb command.
-        clearDisallowAddManagedProfileRestriction();
-        try {
-            final int userId = createManagedProfile(mPrimaryUserId);
-            installAppAsUser(apkName, userId);
-            setProfileOwnerOrFail(adminReceiverClassName, userId);
-            startUserAndWait(userId);
-            runDeviceTestsAsUser(
-                    packageName,
-                    MANAGEMENT_TEST,
-                    "testIsManagedProfile",
-                    userId);
-            return userId;
-        } finally {
-            // Adding back DISALLOW_ADD_MANAGED_PROFILE.
-            addDisallowAddManagedProfileRestriction();
-        }
+        final int userId = createManagedProfile(mPrimaryUserId);
+        installAppAsUser(apkName, userId);
+        setProfileOwnerOrFail(adminReceiverClassName, userId);
+        startUserAndWait(userId);
+        runDeviceTestsAsUser(
+                packageName,
+                MANAGEMENT_TEST,
+                "testIsManagedProfile",
+                userId);
+        return userId;
     }
 
     /** Returns the user id of the newly created secondary user */
@@ -671,50 +643,6 @@
     }
 
     /**
-     * Clear {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
-     */
-    private void clearDisallowAddManagedProfileRestriction() throws Exception {
-        runDeviceTestsAsUser(
-                COMP_DPC_PKG,
-                USER_RESTRICTION_TEST,
-                "testClearDisallowAddManagedProfileRestriction",
-                mPrimaryUserId);
-    }
-
-    /**
-     * Add {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
-     */
-    private void addDisallowAddManagedProfileRestriction() throws Exception {
-        runDeviceTestsAsUser(
-                COMP_DPC_PKG,
-                USER_RESTRICTION_TEST,
-                "testAddDisallowAddManagedProfileRestriction",
-                mPrimaryUserId);
-    }
-
-    /**
-     * Clear {@link android.os.UserManager#DISALLOW_REMOVE_MANAGED_PROFILE}.
-     */
-    private void clearDisallowRemoveManagedProfileRestriction() throws Exception {
-        runDeviceTestsAsUser(
-                COMP_DPC_PKG,
-                USER_RESTRICTION_TEST,
-                "testClearDisallowRemoveManagedProfileRestriction",
-                mPrimaryUserId);
-    }
-
-    /**
-     * Add {@link android.os.UserManager#DISALLOW_REMOVE_MANAGED_PROFILE}.
-     */
-    private void addDisallowRemoveManagedProfileRestriction() throws Exception {
-        runDeviceTestsAsUser(
-                COMP_DPC_PKG,
-                USER_RESTRICTION_TEST,
-                "testAddDisallowRemoveManagedProfileRestriction",
-                mPrimaryUserId);
-    }
-
-    /**
      * Add {@link android.os.UserManager#DISALLOW_REMOVE_USER}.
      */
     private void addDisallowRemoveUserRestriction() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
index 640eb8b..5feb67a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
@@ -320,6 +320,71 @@
         runCrossProfileCalendarTestsWhenNotWhitelisted();
     }
 
+    @Test
+    public void testSetCrossProfilePackages_notProfileOwner_throwsSecurityException()
+            throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG,
+                ".CrossProfileTest",
+                "testSetCrossProfilePackages_notProfileOwner_throwsSecurityException",
+                mProfileUserId);
+    }
+
+    @Test
+    public void testGetCrossProfilePackages_notProfileOwner_throwsSecurityException()
+            throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG,
+                ".CrossProfileTest",
+                "testGetCrossProfilePackages_notProfileOwner_throwsSecurityException",
+                mProfileUserId);
+    }
+
+    @Test
+    public void testGetCrossProfilePackages_notSet_returnsEmpty()
+            throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG,
+                ".CrossProfileTest",
+                "testGetCrossProfilePackages_notSet_returnsEmpty",
+                mProfileUserId);
+    }
+
+    @Test
+    public void testGetCrossProfilePackages_whenSetTwice_returnsLatestNotConcatenated()
+            throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG,
+                ".CrossProfileTest",
+                "testGetCrossProfilePackages_whenSetTwice_returnsLatestNotConcatenated",
+                mProfileUserId);
+    }
+
+    @Test
+    public void testGetCrossProfilePackages_whenSet_returnsEqual()
+            throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG,
+                ".CrossProfileTest",
+                "testGetCrossProfilePackages_whenSet_returnsEqual",
+                mProfileUserId);
+    }
+
     @FlakyTest
     @Test
     public void testDisallowSharingIntoPersonalFromProfile() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index d4f920a..eb0d46b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -224,6 +224,18 @@
                 "testParentProfileApiDisabled", mProfileUserId);
     }
 
+    @Test
+    public void testCannotCallMethodsOnParentProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ParentProfileTest",
+                "testCannotWipeParentProfile", mProfileUserId);
+
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ParentProfileTest",
+                "testCannotCallAutoTimeMethodsOnParentProfile", mProfileUserId);
+    }
+
     // TODO: This test is not specific to managed profiles, but applies to multi-user in general.
     // Move it to a MultiUserTest class when there is one. Should probably move
     // SetPolicyActivity to a more generic apk too as it might be useful for different kinds
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
index a21d81e..f837274 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
@@ -18,8 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertTrue;
+
 import android.platform.test.annotations.FlakyTest;
-import android.platform.test.annotations.LargeTest;
 
 import com.android.tradefed.device.DeviceNotAvailableException;
 
@@ -40,6 +41,7 @@
     private int mParentUserId = -1;
     protected int mUserId;
     private boolean mHasProfileToRemove = true;
+    private boolean mHasSecondaryProfileToRemove = false;
 
     @Override
     public void setUp() throws Exception {
@@ -73,6 +75,10 @@
             removeOrgOwnedProfile();
             removeUser(mUserId);
         }
+        if (mHasSecondaryProfileToRemove) {
+            removeTestUsers();
+            getDevice().uninstallPackage(DEVICE_ADMIN_PKG);
+        }
         super.tearDown();
     }
 
@@ -145,6 +151,33 @@
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".OrgOwnedProfileOwnerParentTest", mUserId);
     }
 
+    @Test
+    public void testUserRestrictionsSetOnParentAreNotPersisted() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        int secondaryUserId = createUser();
+        setPoAsUser(secondaryUserId);
+        mHasSecondaryProfileToRemove = true;
+
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".UserRestrictionsParentTest",
+                "testAddUserRestriction_onParent", mUserId);
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".UserRestrictionsParentTest",
+                "testHasUserRestriction", mUserId);
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".UserRestrictionsParentTest",
+                "testHasUserRestriction", secondaryUserId);
+        removeOrgOwnedProfile();
+        assertHasNoUser(mUserId);
+        mHasProfileToRemove = false;
+
+        // Make sure the user restrictions are removed before continuing
+        waitForBroadcastIdle();
+
+        // User restrictions are not persist after organization-owned profile owner is removed
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".UserRestrictionsParentTest",
+                "testUserRestrictionAreNotPersisted", secondaryUserId);
+    }
+
     @FlakyTest(bugId = 137088260)
     @Test
     public void testWifi() throws Exception {
@@ -172,4 +205,12 @@
 
         assertThat(listUsers()).doesNotContain(userId);
     }
+
+    private void setPoAsUser(int userId) throws Exception {
+        installAppAsUser(DEVICE_ADMIN_APK, true, true, userId);
+        assertTrue("Failed to set profile owner",
+                setProfileOwner(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS,
+                        userId, /* expectFailure */ false));
+    }
+
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java
index 2a5c117..331b2e2 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java
@@ -17,8 +17,6 @@
 
 import static org.junit.Assert.assertTrue;
 
-import android.platform.test.annotations.FlakyTest;
-
 import com.android.tradefed.device.DeviceNotAvailableException;
 
 import org.junit.Test;
@@ -137,7 +135,6 @@
     }
 
     // Checks restrictions for managed profile.
-    @FlakyTest
     @Test
     public void testUserRestrictions_managedProfileOwnerOnly() throws Exception {
         if (!mHasFeature || !mSupportsMultiUser || !mHasManagedUserFeature) {
@@ -161,7 +158,6 @@
     /**
      * DO + PO combination.  Make sure global DO restrictions are visible on secondary users.
      */
-    @FlakyTest
     @Test
     public void testUserRestrictions_layering() throws Exception {
         if (!mHasFeature || !mSupportsMultiUser) {
@@ -230,7 +226,6 @@
      * DO sets profile global restrictions (only ENSURE_VERIFY_APPS), should affect all
      * users (not a particularly special case but to be sure).
      */
-    @FlakyTest
     @Test
     public void testUserRestrictions_profileGlobalRestrictionsAsDo() throws Exception {
         if (!mHasFeature || !mSupportsMultiUser) {
@@ -252,7 +247,6 @@
      * Managed profile owner sets profile global restrictions (only ENSURE_VERIFY_APPS), should
      * affect all users.
      */
-    @FlakyTest
     @Test
     public void testUserRestrictions_ProfileGlobalRestrictionsAsPo() throws Exception {
         if (!mHasFeature || !mSupportsMultiUser || !mHasManagedUserFeature) {
@@ -276,7 +270,8 @@
 
     /** Installs admin package and makes it a profile owner for a given user. */
     private void setPoAsUser(int userId) throws Exception {
-        installAppAsUser(DEVICE_ADMIN_APK, userId);
+        installAppAsUser(DEVICE_ADMIN_APK, /* grantPermssions= */true,
+                /* dontKillApp= */ true, userId);
         assertTrue("Failed to set profile owner",
                 setProfileOwner(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS,
                         userId, /* expectFailure */ false));
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java
index 49c5b3b..d4111d4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java
@@ -52,7 +52,7 @@
 
     /**
      * Test 11.2.9-2
-     * Tests that the device broadcasts a <DEVICE_VENDOR_ID> message after successfull
+     * Tests that the device broadcasts a <DEVICE_VENDOR_ID> message after successful
      * initialisation and address allocation.
      */
     @Test
diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
index 90b78fc..1356600 100644
--- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
@@ -126,8 +126,8 @@
         assertTrue(jankyDelta < 25);
 
         int gt150msDelta = countFramesAbove(statsAfter, 150) - countFramesAbove(statsBefore, 150);
-        assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first frame
-        assertTrue(gt150msDelta <= 21);
+        assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first 2 frames
+        assertTrue(gt150msDelta <= 22);
         int gt700msDelta = countFramesAbove(statsAfter, 700) - countFramesAbove(statsBefore, 700);
         assertEquals(10, gt700msDelta); // 10 daveys
     }
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
index c43d421..26397ef 100755
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -20,6 +20,7 @@
 import static android.system.OsConstants.*;
 
 import android.annotation.Nullable;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -33,6 +34,7 @@
 import android.net.ProxyInfo;
 import android.net.VpnService;
 import android.net.wifi.WifiManager;
+import android.provider.Settings;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemProperties;
@@ -62,8 +64,11 @@
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -95,6 +100,13 @@
  */
 public class VpnTest extends InstrumentationTestCase {
 
+    // These are neither public nor @TestApi.
+    // TODO: add them to @TestApi.
+    private static final String PRIVATE_DNS_MODE_SETTING = "private_dns_mode";
+    private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+    private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+    private static final String PRIVATE_DNS_SPECIFIER_SETTING = "private_dns_specifier";
+
     public static String TAG = "VpnTest";
     public static int TIMEOUT_MS = 3 * 1000;
     public static int SOCKET_TIMEOUT_MS = 100;
@@ -112,6 +124,9 @@
     final Object mLock = new Object();
     final Object mLockShutdown = new Object();
 
+    private String mOldPrivateDnsMode;
+    private String mOldPrivateDnsSpecifier;
+
     private boolean supportedHardware() {
         final PackageManager pm = getInstrumentation().getContext().getPackageManager();
         return !pm.hasSystemFeature("android.hardware.type.watch");
@@ -123,6 +138,7 @@
 
         mNetwork = null;
         mCallback = null;
+        storePrivateDnsSetting();
 
         mDevice = UiDevice.getInstance(getInstrumentation());
         mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
@@ -137,6 +153,7 @@
 
     @Override
     public void tearDown() throws Exception {
+        restorePrivateDnsSetting();
         mRemoteSocketFactoryClient.unbind();
         if (mCallback != null) {
             mCM.unregisterNetworkCallback(mCallback);
@@ -567,6 +584,95 @@
         }
     }
 
+    private ContentResolver getContentResolver() {
+        return getInstrumentation().getContext().getContentResolver();
+    }
+
+    private boolean isPrivateDnsInStrictMode() {
+        return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(
+                Settings.Global.getString(getContentResolver(), PRIVATE_DNS_MODE_SETTING));
+    }
+
+    private void storePrivateDnsSetting() {
+        mOldPrivateDnsMode = Settings.Global.getString(getContentResolver(),
+                PRIVATE_DNS_MODE_SETTING);
+        mOldPrivateDnsSpecifier = Settings.Global.getString(getContentResolver(),
+                PRIVATE_DNS_SPECIFIER_SETTING);
+    }
+
+    private void restorePrivateDnsSetting() {
+        Settings.Global.putString(getContentResolver(), PRIVATE_DNS_MODE_SETTING,
+                mOldPrivateDnsMode);
+        Settings.Global.putString(getContentResolver(), PRIVATE_DNS_SPECIFIER_SETTING,
+                mOldPrivateDnsSpecifier);
+    }
+
+    // TODO: replace with CtsNetUtils.awaitPrivateDnsSetting in Q or above.
+    private void expectPrivateDnsHostname(final String hostname) throws Exception {
+        final NetworkRequest request = new NetworkRequest.Builder()
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+                .build();
+        final CountDownLatch latch = new CountDownLatch(1);
+        final NetworkCallback callback = new NetworkCallback() {
+            @Override
+            public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
+                if (network.equals(mNetwork) &&
+                        Objects.equals(lp.getPrivateDnsServerName(), hostname)) {
+                    latch.countDown();
+                }
+            }
+        };
+
+        mCM.registerNetworkCallback(request, callback);
+
+        try {
+            assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms",
+                    latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mCM.unregisterNetworkCallback(callback);
+        }
+    }
+
+    private void setAndVerifyPrivateDns(boolean strictMode) throws Exception {
+        final ContentResolver cr = getInstrumentation().getContext().getContentResolver();
+        String privateDnsHostname;
+
+        if (strictMode) {
+            privateDnsHostname = "vpncts-nx.metric.gstatic.com";
+            Settings.Global.putString(cr, PRIVATE_DNS_SPECIFIER_SETTING, privateDnsHostname);
+            Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING,
+                    PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+        } else {
+            Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING, PRIVATE_DNS_MODE_OPPORTUNISTIC);
+            privateDnsHostname = null;
+        }
+
+        expectPrivateDnsHostname(privateDnsHostname);
+
+        String randomName = "vpncts-" + new Random().nextInt(1000000000) + "-ds.metric.gstatic.com";
+        if (strictMode) {
+            // Strict mode private DNS is enabled. DNS lookups should fail, because the private DNS
+            // server name is invalid.
+            try {
+                InetAddress.getByName(randomName);
+                fail("VPN DNS lookup should fail with private DNS enabled");
+            } catch (UnknownHostException expected) {
+            }
+        } else {
+            // Strict mode private DNS is disabled. DNS lookup should succeed, because the VPN
+            // provides no DNS servers, and thus DNS falls through to the default network.
+            assertNotNull("VPN DNS lookup should succeed with private DNS disabled",
+                    InetAddress.getByName(randomName));
+        }
+    }
+
+    // Tests that strict mode private DNS is used on VPNs.
+    private void checkStrictModePrivateDns() throws Exception {
+        final boolean initialMode = isPrivateDnsInStrictMode();
+        setAndVerifyPrivateDns(!initialMode);
+        setAndVerifyPrivateDns(initialMode);
+    }
+
     public void testDefault() throws Exception {
         if (!supportedHardware()) return;
         // If adb TCP port opened, this test may running by adb over network.
@@ -598,6 +704,9 @@
         assertSocketClosed(fd, TEST_HOST);
 
         checkTrafficOnVpn();
+
+        checkStrictModePrivateDns();
+
         receiver.unregisterQuietly();
     }
 
@@ -615,6 +724,8 @@
         assertSocketClosed(fd, TEST_HOST);
 
         checkTrafficOnVpn();
+
+        checkStrictModePrivateDns();
     }
 
     public void testAppDisallowed() throws Exception {
diff --git a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
index 82518da..cdd87fb 100644
--- a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
@@ -228,14 +228,19 @@
      */
     @CddTest(requirement="9.7")
     public void testConfigHardwareMitigations() throws Exception {
+        String mitigations[];
+
         if (PropertyUtil.getFirstApiLevel(mDevice) < 28) {
             return;
         }
 
         if (CpuFeatures.isArm64(mDevice) && !CpuFeatures.kernelVersionLessThan(mDevice, 4, 4)) {
-            for (String mitigation : lookupMitigations()) {
-                assertTrue("Linux kernel must have " + mitigation + " enabled.",
-                        configSet.contains(mitigation));
+            mitigations = lookupMitigations();
+            if (mitigations != null) {
+                for (String mitigation : mitigations) {
+                    assertTrue("Linux kernel must have " + mitigation + " enabled.",
+                            configSet.contains(mitigation));
+                }
             }
         } else if (CpuFeatures.isX86(mDevice)) {
             assertTrue("Linux kernel must have KPTI enabled: CONFIG_PAGE_TABLE_ISOLATION=y",
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp
index af352aa..b31a788 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp
@@ -23,7 +23,6 @@
         "libutils",
         "liblog",
         "libmedia",
-        "libsoundtrigger",
         "libgui",
     ],
     ldflags: [
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.mk
index c368779..d6efe13 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.mk
@@ -7,7 +7,7 @@
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
-LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.mk
index f7968eb..d7f4ae9 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.mk
@@ -7,7 +7,7 @@
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
-LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp
index e811dd3..2604551 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp
@@ -22,5 +22,6 @@
         "libbinder",
         "libandroid",
         "libaudioclient",
+        "libaudiofoundation",
     ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp
index 3fc6329..0c64210 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp
@@ -75,10 +75,11 @@
   gEffect = NULL;
   pthread_t pt;
   const sp<IAudioFlinger> &audioFlinger = AudioSystem::get_audio_flinger();
+  AudioDeviceTypeAddr device;
 
   for (i=0; i<100; i++) {
     gEffect = audioFlinger->createEffect(&descriptor, effectClient, priority,
-                                         io, sessionId, opPackageName, getpid(),
+                                         io, sessionId, device, opPackageName, getpid(),
                                          &err, &id, &enabled);
     if (gEffect == NULL || err != NO_ERROR) {
       return -1;
diff --git a/hostsidetests/securitybulletin/securityPatch/pac/Android.mk b/hostsidetests/securitybulletin/securityPatch/pac/Android.mk
index bd9c07d..1960664 100644
--- a/hostsidetests/securitybulletin/securityPatch/pac/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/pac/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_SHARED_LIBRARIES := \
         libpac \
 
-LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 93b5cd9..3e4f5b3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -408,27 +408,12 @@
                     AdbUtils.runCommandLine("rm /data/local/tmp/" + tempFile, device);
                 }
             }
-            if (test_failed == true) {
-                Assert.fail("PoC was interrupted");
+            if (test_failed) {
+                fail("PoC was interrupted");
             }
         }
         if (t.isAlive()) {
             Assert.fail("PoC not completed within timeout of " + timeout + " ms");
         }
     }
-
-    /**
-     * Raises assert exception upon crash/error occurence
-     *
-     * @param crashPatternList array of crash log patterns to be checked for
-     * @param logcat String to be parsed
-     */
-    public static void checkCrash(String crashPatternList[], String logcat)
-            throws Exception {
-        for (String crashPattern : crashPatternList) {
-            assertFalse("Crash log pattern found!",
-                    Pattern.compile(crashPattern, Pattern.MULTILINE)
-                            .matcher(logcat).find());
-        }
-    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index bbfd78e..ecc086c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -45,41 +45,6 @@
      * before any existing test methods
      ****************************************************************/
 
-
-    /**
-     * Checks for linker errors
-     *
-     * @param binaryName name of the binary
-     * @param logcat String to be parsed
-     */
-    public static boolean isLinkerErrorPresent(String binaryName, String logcat)
-            throws Exception {
-        return Pattern
-                .compile("CANNOT LINK EXECUTABLE \"" + TMP_FILE_PATH
-                        + binaryName + "\"", Pattern.MULTILINE)
-                .matcher(logcat).find();
-    }
-
-    /**
-     * Checks for crash
-     *
-     * @param binaryName Name of the binary
-     * @param errPattern error patterns to be checked for
-     * @param logcat String to be parsed
-     */
-    public static void checkCrash(String binaryName, String errPattern[],
-            String logcat) throws Exception {
-        String genericCrashPattern[] = {
-                "name: " + binaryName + "  >>> " + TMP_FILE_PATH + binaryName
-                        + " <<<\n.*?SIGABRT",
-                "name: " + binaryName + "  >>> " + TMP_FILE_PATH + binaryName
-                        + " <<<\n.*?SIGSEGV"};
-        AdbUtils.checkCrash(genericCrashPattern, logcat);
-        if (errPattern != null) {
-            AdbUtils.checkCrash(errPattern, logcat);
-        }
-    }
-
     /**
      * Pushes input files, runs the PoC and checks for crash and hang
      *
@@ -91,7 +56,7 @@
      */
     public static void runMediaTest(String binaryName,
             String inputFiles[], String arguments, ITestDevice device,
-            String errPattern[]) throws Exception {
+            String processPatternStrings[]) throws Exception {
         if (inputFiles != null) {
             for (String tempFile : inputFiles) {
                 AdbUtils.pushResource(RESOURCE_ROOT + tempFile,
@@ -110,10 +75,10 @@
                 }
             }
         }, TIMEOUT_SEC * 1000, device, inputFiles);
-        String logcatOut = AdbUtils.runCommandLine("logcat -d", device);
-        boolean linkerErrorFound = isLinkerErrorPresent(binaryName, logcatOut);
-        if (!linkerErrorFound) {
-            checkCrash(binaryName, errPattern, logcatOut);
+
+        AdbUtils.assertNoCrashes(device, binaryName);
+        if (processPatternStrings != null) {
+            AdbUtils.assertNoCrashes(device, processPatternStrings);
         }
     }
 }
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index 2117543..5af74b4 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -274,7 +274,17 @@
     public void testGetActiveStagedSessions() throws Exception {
         PackageInstaller packageInstaller = getPackageInstaller();
         int firstSessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(firstSessionId);
         int secondSessionId = stageSingleApk(TestApp.B1).assertSuccessful().getSessionId();
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(secondSessionId);
         List<Integer> stagedSessionIds = packageInstaller.getActiveStagedSessions()
                 .stream().map(s -> s.getSessionId()).collect(Collectors.toList());
         assertThat(stagedSessionIds).hasSize(2);
@@ -293,8 +303,17 @@
     public void testGetActiveStagedSessions_MultiApkSession() throws Exception {
         int firstSessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
                 .assertSuccessful().getSessionId();
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(firstSessionId);
         int secondSessionId = stageMultipleApks(TestApp.C1)
                 .assertSuccessful().getSessionId();
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        waitForIsReadyBroadcast(secondSessionId);
         List<Integer> stagedSessionIds = getPackageInstaller().getActiveStagedSessions()
                 .stream().map(s -> s.getSessionId()).collect(Collectors.toList());
         assertThat(stagedSessionIds).hasSize(2);
@@ -684,8 +703,7 @@
     public void testRejectsApexDifferentCertificate() throws Exception {
         int sessionId = stageSingleApk(Apex2DifferentCertificate)
                 .assertSuccessful().getSessionId();
-        PackageInstaller.SessionInfo info =
-                SessionUpdateBroadcastReceiver.sessionBroadcasts.poll(60, TimeUnit.SECONDS);
+        PackageInstaller.SessionInfo info = waitForBroadcast(sessionId);
         assertThat(info.getSessionId()).isEqualTo(sessionId);
         assertThat(info).isStagedSessionFailed();
         assertThat(info.getStagedSessionErrorMessage()).contains("is not compatible with the one "
@@ -776,33 +794,59 @@
     // Should fail to stage multiple sessions when check-point is not available
     @Test
     public void testFailStagingMultipleSessionsIfNoCheckPoint() throws Exception {
-        stageSingleApk(TestApp.A1).assertSuccessful();
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
         StageSessionResult failedSessionResult = stageSingleApk(TestApp.B1);
         assertThat(failedSessionResult.getErrorMessage()).contains(
                 "Cannot stage multiple sessions without checkpoint support");
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
     }
 
     @Test
     public void testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk() throws Exception {
-        stageSingleApk(TestApp.A1).assertSuccessful();
+        int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
         StageSessionResult failedSessionResult = stageSingleApk(TestApp.A1);
         assertThat(failedSessionResult.getErrorMessage()).contains(
                 "has been staged already by session");
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
     }
 
     @Test
     public void testAllowNonOverlappingMultipleStagedInstall_MultiPackageSinglePackage_Apk()
             throws Exception {
-        stageMultipleApks(TestApp.A1, TestApp.B1).assertSuccessful();
-        stageSingleApk(TestApp.C1).assertSuccessful();
+        int firstSessionId = stageMultipleApks(TestApp.A1, TestApp.B1).assertSuccessful()
+                .getSessionId();
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(firstSessionId);
+        int secondSessionId = stageSingleApk(TestApp.C1).assertSuccessful().getSessionId();
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(secondSessionId);
     }
 
     @Test
     public void testFailOverlappingMultipleStagedInstall_BothMultiPackage_Apk() throws Exception {
-        stageMultipleApks(TestApp.A1, TestApp.B1).assertSuccessful();
+        int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1).assertSuccessful().getSessionId();
         StageSessionResult failedSessionResult = stageMultipleApks(TestApp.A2, TestApp.C1);
         assertThat(failedSessionResult.getErrorMessage()).contains(
                 "has been staged already by session");
+        // Currently abandoning a session before pre-reboot verification finishes might result in
+        // a system_server crash. Before that issue is resolved we need to manually wait for
+        // pre-reboot verification to finish before abandoning sessions.
+        // TODO(b/145925842): remove following two lines after fixing the bug.
+        waitForIsReadyBroadcast(sessionId);
     }
 
     @Test
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex
index 6b838dd..e3bdbdd 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
index 91096d5..5f05659 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
index 23ae628..680dfb2 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
index 0438269..6103b50 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex
index 8f38f3f..cf0e800 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex
index b43ad69..0af717c 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex
index 81f0ee9..d3f7014 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
index 4b7ae32..05f1cbb 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
index 1bc260d..37acf43 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
index 0066f3a..c82c1e0 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
index afd33f9..d9905a8 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
index 71fa484..dfb6757 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex
index 77c5679..ca32c0d 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex
index 124f769..befa6b2 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
index b9abc3d..6e5b1c6 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
Binary files differ
diff --git a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
index 5e9eac6..b1705ad 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
@@ -72,6 +72,23 @@
         }
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (PERFETTO_TESTS_ENABLED) {
+            //Deadline to finish trace collection
+            final long deadLine = System.currentTimeMillis() + 10000;
+            while (isSystemTracingEnabled()) {
+                if (System.currentTimeMillis() > deadLine) {
+                    CLog.w("/sys/kernel/debug/tracing/tracing_on is still 1 after 10 secs : " + isSystemTracingEnabled());
+                    break;
+                }
+                CLog.d("Waiting to finish collecting traces. ");
+                Thread.sleep(WAIT_TIME_SHORT);
+            }
+        }
+    }
+
     // Tests that anomaly detection for count works.
     // Also tests that anomaly detection works when spanning multiple buckets.
     public void testCountAnomalyDetection() throws Exception {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
index 070d3f4..ff65335 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
@@ -40,7 +40,7 @@
     private static final int WAIT_TIME_FOR_CONFIG_UPDATE_MS = 200;
     // ActivityManager can take a while to register screen state changes, mandating an extra delay.
     private static final int WAIT_TIME_FOR_CONFIG_AND_SCREEN_MS = 1_000;
-    private static final int EXTRA_WAIT_TIME_MS = 1_000; // as buffer when proc state changing.
+    private static final int EXTRA_WAIT_TIME_MS = 5_000; // as buffer when proc state changing.
     private static final int STATSD_REPORT_WAIT_TIME_MS = 500; // make sure statsd finishes log.
 
     private static final String FEATURE_WATCH = "android.hardware.type.watch";
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index fd77425..540ff9b 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -635,6 +635,12 @@
         if (!hasFeature(FEATURE_WATCH, false)) return;
         final int atomTag = Atom.MEDIA_CODEC_STATE_CHANGED_FIELD_NUMBER;
 
+        // 5 seconds. Starting video tends to be much slower than most other
+        // tests on slow devices. This is unfortunate, because it leaves a
+        // really big slop in assertStatesOccurred.  It would be better if
+        // assertStatesOccurred had a tighter range on large timeouts.
+        final int waitTime = 5000;
+
         Set<Integer> onState = new HashSet<>(
                 Arrays.asList(MediaCodecStateChanged.State.ON_VALUE));
         Set<Integer> offState = new HashSet<>(
@@ -646,13 +652,14 @@
         createAndUploadConfig(atomTag, true);  // True: uses attribution.
         Thread.sleep(WAIT_TIME_SHORT);
 
-        runActivity("VideoPlayerActivity", "action", "action.play_video");
+        runActivity("VideoPlayerActivity", "action", "action.play_video",
+            waitTime);
 
         // Sorted list of events in order in which they occurred.
         List<EventMetricData> data = getEventMetricDataList();
 
         // Assert that the events happened in the expected order.
-        assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
+        assertStatesOccurred(stateSet, data, waitTime,
                 atom -> atom.getMediaCodecStateChanged().getState().getNumber());
     }
 
@@ -674,7 +681,7 @@
         createAndUploadConfig(atomTag, false);
 
         runActivity("StatsdCtsForegroundActivity", "action", "action.show_application_overlay",
-                3_000);
+                5_000);
 
         // Sorted list of events in order in which they occurred.
         List<EventMetricData> data = getEventMetricDataList();
@@ -1134,7 +1141,7 @@
         // Start test app.
         try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
                 "action.show_notification")) {
-            Thread.sleep(WAIT_TIME_SHORT);
+            Thread.sleep(WAIT_TIME_LONG);
             // Trigger a pull and wait for new pull before killing the process.
             setAppBreadcrumbPredicate();
             Thread.sleep(WAIT_TIME_LONG);
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
index 889763b..9aafbad 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
@@ -53,6 +53,7 @@
         plugInUsb();
     }
 
+    /*
     public void testConnectivityStateChange() throws Exception {
         if (!hasFeature(FEATURE_WIFI, true)) return;
         if (!hasFeature(FEATURE_WATCH, false)) return;
@@ -77,6 +78,7 @@
         assertThat(countMetricData.get(0).getBucketInfo(0).getCount()).isEqualTo(
                 (long) batterystatsProto.getSystem().getMisc().getNumConnectivityChanges());
     }
+    */
 
     public void testPowerUse() throws Exception {
         if (statsdDisabled()) {
@@ -117,67 +119,6 @@
         assertThat(bsPowerNas).isGreaterThan(ALLOWED_FRACTIONAL_DIFFERENCE * statsdPowerNas);
     }
 
-    public void testPowerBlameUid() throws Exception {
-        if (statsdDisabled()) {
-            return;
-        }
-        if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return;
-        resetBatteryStats();
-        unplugDevice();
-
-        final double ALLOWED_FRACTIONAL_DIFFERENCE = 0.8; // ratio that statsd and bs can differ
-
-        StatsdConfig.Builder config = getPulledConfig();
-        addGaugeAtomWithDimensions(config, Atom.DEVICE_CALCULATED_POWER_BLAME_UID_FIELD_NUMBER,
-                null);
-        uploadConfig(config);
-        unplugDevice();
-
-        Thread.sleep(WAIT_TIME_LONG);
-        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
-        Thread.sleep(WAIT_TIME_LONG);
-
-        setAppBreadcrumbPredicate();
-        BatteryStatsProto batterystatsProto = getBatteryStatsProto();
-        Thread.sleep(WAIT_TIME_LONG);
-        List<Atom> atomList = getGaugeMetricDataList();
-
-        // Extract statsd data
-        boolean uidFound = false;
-        int uid = getUid();
-        long statsdUidPowerNas = 0;
-        for (Atom atom : atomList) {
-            DeviceCalculatedPowerBlameUid item = atom.getDeviceCalculatedPowerBlameUid();
-            if (item.getUid() == uid) {
-                assertWithMessage("Found multiple power values for uid %s", uid)
-                        .that(uidFound).isFalse();
-                uidFound = true;
-                statsdUidPowerNas = item.getPowerNanoAmpSecs();
-            }
-        }
-        assertWithMessage("Statsd: No power value for uid %s", uid).that(uidFound).isTrue();
-        assertWithMessage("Statsd: Non-positive power value for uid %s", uid)
-                .that(statsdUidPowerNas).isGreaterThan(0L);
-
-        // Extract batterystats data
-        double bsUidPowerNas = -1;
-        boolean hadUid = false;
-        for (UidProto uidProto : batterystatsProto.getUidsList()) {
-            if (uidProto.getUid() == uid) {
-                hadUid = true;
-                bsUidPowerNas = uidProto.getPowerUseItem().getComputedPowerMah()
-                        * 1_000_000L * 3600L; /* mAh to nAs */;
-            }
-        }
-        assertWithMessage("Batterystats: No power value for uid %s", uid).that(hadUid).isTrue();
-        assertWithMessage("BatteryStats: Non-positive power value for uid %s", uid)
-                .that(bsUidPowerNas).isGreaterThan(0d);
-
-        assertThat((double) statsdUidPowerNas)
-                .isGreaterThan(ALLOWED_FRACTIONAL_DIFFERENCE * bsUidPowerNas);
-        assertThat(bsUidPowerNas).isGreaterThan(ALLOWED_FRACTIONAL_DIFFERENCE * statsdUidPowerNas);
-    }
-
     public void testServiceStartCount() throws Exception {
         final String fileName = "BATTERYSTATS_SERVICE_START_COUNT.pbtxt";
         StatsdConfig config = createValidationUtil().getConfig(fileName);
diff --git a/tests/AlarmManager/AndroidTest.xml b/tests/AlarmManager/AndroidTest.xml
index f44ae93..4369acc 100644
--- a/tests/AlarmManager/AndroidTest.xml
+++ b/tests/AlarmManager/AndroidTest.xml
@@ -19,6 +19,7 @@
     <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" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/accessibility/AndroidManifest.xml b/tests/accessibility/AndroidManifest.xml
index d4cea0f..c9e0c71 100644
--- a/tests/accessibility/AndroidManifest.xml
+++ b/tests/accessibility/AndroidManifest.xml
@@ -57,11 +57,31 @@
                        android:resource="@xml/speaking_and_vibrating_accessibilityservice" />
         </service>
 
+        <service android:name=".AccessibilityButtonService"
+                 android:label="@string/title_accessibility_button_service"
+                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService"/>
+            </intent-filter>
+            <meta-data android:name="android.accessibilityservice"
+                       android:resource="@xml/accessibility_button_service" />
+        </service>
+
         <activity
             android:label="@string/some_description"
             android:name=".DummyActivity"
             android:screenOrientation="locked"/>
 
+        <activity android:name=".AccessibilityShortcutTargetActivity"
+                  android:label="@string/shortcut_target_title">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.ACCESSIBILITY_SHORTCUT_TARGET" />
+            </intent-filter>
+            <meta-data android:name="android.accessibilityshortcut.target"
+                       android:resource="@xml/shortcut_target_activity"/>
+        </activity>
+
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/accessibility/res/layout/shortcut_target.xml b/tests/accessibility/res/layout/shortcut_target.xml
new file mode 100644
index 0000000..42d10a0
--- /dev/null
+++ b/tests/accessibility/res/layout/shortcut_target.xml
@@ -0,0 +1,28 @@
+<?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:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:gravity="center"
+              android:orientation="vertical">
+    <Button
+        android:id="@+id/targetActionBtn"
+        android:text="@string/shortcut_button_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+</LinearLayout>
diff --git a/tests/accessibility/res/values/strings.xml b/tests/accessibility/res/values/strings.xml
index 7bd62af..de1539a 100644
--- a/tests/accessibility/res/values/strings.xml
+++ b/tests/accessibility/res/values/strings.xml
@@ -26,6 +26,9 @@
     <!-- String title for the vibrating accessibility service -->
     <string name="title_speaking_and_vibrating_accessibility_service">Speaking and Vibrating Accessibility Service</string>
 
+    <!-- String title for the accessibility button service -->
+    <string name="title_accessibility_button_service">Accessibility Button Service</string>
+
     <!-- Description of the speaking accessibility service -->
     <string name="some_description">Some description</string>
 
@@ -35,4 +38,10 @@
     <!-- Summary of the speaking accessibility service -->
     <string name="some_summary">Some summary</string>
 
+    <!-- String title for the button of shortcut target activity -->
+    <string name="shortcut_button_title">Action</string>
+
+    <!-- String title for the shortcut target activity -->
+    <string name="shortcut_target_title">Shortcut Target</string>
+
 </resources>
diff --git a/tests/accessibility/res/xml/accessibility_button_service.xml b/tests/accessibility/res/xml/accessibility_button_service.xml
new file mode 100644
index 0000000..d475266
--- /dev/null
+++ b/tests/accessibility/res/xml/accessibility_button_service.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+                       android:description="@string/some_description"
+                       android:accessibilityEventTypes="typeAllMask"
+                       android:accessibilityFeedbackType="feedbackGeneric"
+                       android:accessibilityFlags="flagRequestAccessibilityButton"
+                       android:notificationTimeout="0" />
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/gradientdrawable_stroke_tint.xml b/tests/accessibility/res/xml/shortcut_target_activity.xml
similarity index 72%
rename from tests/tests/graphics/res/drawable/gradientdrawable_stroke_tint.xml
rename to tests/accessibility/res/xml/shortcut_target_activity.xml
index 13404bc..b258d3f 100644
--- a/tests/tests/graphics/res/drawable/gradientdrawable_stroke_tint.xml
+++ b/tests/accessibility/res/xml/shortcut_target_activity.xml
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
+
 <!--
   ~ Copyright (C) 2019 The Android Open Source Project
   ~
@@ -14,11 +15,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle" >
-  <corners android:radius="5dp" />
-  <stroke
-      android:width="20dp"
-      android:color="@android:color/white"/>
-</shape>
\ No newline at end of file
+
+<accessibility-shortcut-target xmlns:android="http://schemas.android.com/apk/res/android"
+                               android:description="@string/some_description"
+                               android:summary="@string/some_summary"
+/>
\ No newline at end of file
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityButtonService.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityButtonService.java
new file mode 100644
index 0000000..3b4b8fd
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityButtonService.java
@@ -0,0 +1,25 @@
+/*
+ * 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.accessibility.cts;
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService;
+
+/**
+ * An accessibility service that requests accessibility button.
+ */
+public class AccessibilityButtonService extends InstrumentedAccessibilityService {
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 274d13c..f1eab6c 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -17,10 +17,6 @@
 package android.view.accessibility.cts;
 
 import static android.accessibility.cts.common.InstrumentedAccessibilityService.TIMEOUT_SERVICE_ENABLE;
-import static android.accessibility.cts.common.ServiceControlUtils.getEnabledServices;
-import static android.accessibility.cts.common.ServiceControlUtils.waitForConditionWithServiceStateChange;
-
-import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -38,9 +34,6 @@
 import android.content.Context;
 import android.content.pm.ServiceInfo;
 import android.os.Handler;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-import android.text.TextUtils;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
@@ -444,64 +437,6 @@
         }
     }
 
-    @AppModeFull
-    @Test
-    public void performShortcut_withoutPermission_fails() {
-        UiAutomation uiAutomation = sInstrumentation.getUiAutomation(
-                UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
-
-        String originalShortcut = configureShortcut(
-                uiAutomation, SpeakingAccessibilityService.COMPONENT_NAME.flattenToString());
-        try {
-            mAccessibilityManager.performAccessibilityShortcut();
-            fail("No security exception thrown when performing shortcut without permission");
-        } catch (SecurityException e) {
-            // Expected
-        } finally {
-            configureShortcut(uiAutomation, originalShortcut);
-            uiAutomation.destroy();
-        }
-        assertTrue(TextUtils.isEmpty(getEnabledServices(mTargetContext.getContentResolver())));
-    }
-
-    @AppModeFull
-    @Test
-    public void performShortcut_withPermission_succeeds() {
-        UiAutomation uiAutomation = sInstrumentation.getUiAutomation(
-                UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
-
-        String originalShortcut = configureShortcut(
-                uiAutomation, SpeakingAccessibilityService.COMPONENT_NAME.flattenToString());
-        try {
-            runWithShellPermissionIdentity(uiAutomation,
-                    () -> mAccessibilityManager.performAccessibilityShortcut());
-            // Make sure the service starts up
-            final SpeakingAccessibilityService service =
-                    SpeakingAccessibilityService.getInstanceForClass(
-                    SpeakingAccessibilityService.class, TIMEOUT_SERVICE_ENABLE);
-            assertTrue("Speaking accessibility service starts up", service != null);
-        } finally {
-            configureShortcut(uiAutomation, originalShortcut);
-            uiAutomation.destroy();
-        }
-    }
-
-    private String configureShortcut(UiAutomation uiAutomation, String shortcutService) {
-        String currentService = Settings.Secure.getString(mTargetContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
-        putSecureSetting(uiAutomation, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
-                shortcutService);
-        if (shortcutService != null) {
-            runWithShellPermissionIdentity(uiAutomation, () ->
-                    waitForConditionWithServiceStateChange(mTargetContext, () -> TextUtils.equals(
-                            mAccessibilityManager.getAccessibilityShortcutService(),
-                            shortcutService),
-                            TIMEOUT_SERVICE_ENABLE,
-                            "accessibility shortcut set to test service"));
-        }
-        return currentService;
-    }
-
     private void assertAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
             boolean expectedValue, Object waitObject, String message)
             throws Exception {
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTargetActivity.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTargetActivity.java
new file mode 100644
index 0000000..921a769
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTargetActivity.java
@@ -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.
+ */
+
+package android.view.accessibility.cts;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.accessibility.cts.R;
+
+/**
+ * The accessibility shortcut target activity.
+ */
+public class AccessibilityShortcutTargetActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.shortcut_target);
+    }
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTest.java
new file mode 100644
index 0000000..5f61cd2
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTest.java
@@ -0,0 +1,458 @@
+/*
+ * 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.accessibility.cts;
+
+import static android.accessibility.cts.common.InstrumentedAccessibilityService.TIMEOUT_SERVICE_ENABLE;
+import static android.accessibility.cts.common.ServiceControlUtils.waitForConditionWithServiceStateChange;
+import static android.app.UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
+import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
+import android.accessibility.cts.common.ShellCommandBuilder;
+import android.accessibilityservice.AccessibilityButtonController;
+import android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback;
+import android.accessibilityservice.AccessibilityService;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.app.Service;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Tests accessibility shortcut related functionality
+ */
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityShortcutTest {
+    private static final int ACCESSIBILITY_BUTTON = 0;
+    private static final int ACCESSIBILITY_SHORTCUT_KEY = 1;
+
+    private static final String ACCESSIBILITY_BUTTON_TARGET_COMPONENT =
+            "accessibility_button_target_component";
+
+    private static final char DELIMITER = ':';
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    private static Instrumentation sInstrumentation;
+    private static UiAutomation sUiAutomation;
+
+    private final InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService>
+            mServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
+                    SpeakingAccessibilityService.class, false);
+
+    private final InstrumentedAccessibilityServiceTestRule<AccessibilityButtonService>
+            mA11yButtonServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
+            AccessibilityButtonService.class, false);
+
+    private final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+            new AccessibilityDumpOnFailureRule();
+
+    @Rule
+    public final RuleChain mRuleChain = RuleChain
+            .outerRule(mServiceRule)
+            .around(mA11yButtonServiceRule)
+            .around(mDumpOnFailureRule);
+
+    private Context mTargetContext;
+    private ContentResolver mContentResolver;
+    private AccessibilityManager mAccessibilityManager;
+
+    private ActivityMonitor mActivityMonitor;
+    private Activity mShortcutTargetActivity;
+
+    private String mSpeakingA11yServiceName;
+    private String mShortcutTargetActivityName;
+    private String mA11yButtonServiceName;
+
+    // These are the current shortcut states before doing the tests. Roll back them after the tests.
+    private String[] mA11yShortcutTargets;
+    private String[] mA11yButtonTargets;
+    private List<String> mA11yShortcutTargetList;
+    private List<String> mA11yButtonTargetList;
+
+    @BeforeClass
+    public static void oneTimeSetup() {
+        sInstrumentation = InstrumentationRegistry.getInstrumentation();
+        sUiAutomation = sInstrumentation.getUiAutomation(FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+    }
+
+    @AfterClass
+    public static void postTestTearDown() {
+        sUiAutomation.destroy();
+    }
+
+    @Before
+    public void setUp() {
+        mTargetContext = sInstrumentation.getTargetContext();
+        mContentResolver = mTargetContext.getContentResolver();
+        mAccessibilityManager = (AccessibilityManager) mTargetContext.getSystemService(
+                Service.ACCESSIBILITY_SERVICE);
+        mSpeakingA11yServiceName = new ComponentName(mTargetContext,
+                SpeakingAccessibilityService.class).flattenToString();
+        mShortcutTargetActivityName = new ComponentName(mTargetContext,
+                AccessibilityShortcutTargetActivity.class).flattenToString();
+        mA11yButtonServiceName = new ComponentName(mTargetContext,
+                AccessibilityButtonService.class).flattenToString();
+        mActivityMonitor = new ActivityMonitor(
+                AccessibilityShortcutTargetActivity.class.getName(), null, false);
+        sInstrumentation.addMonitor(mActivityMonitor);
+
+        // Reads current shortcut states.
+        readShortcutStates();
+    }
+
+    @After
+    public void tearDown() {
+        if (mActivityMonitor != null) {
+            sInstrumentation.removeMonitor(mActivityMonitor);
+        }
+        if (mShortcutTargetActivity != null) {
+            sInstrumentation.runOnMainSync(() -> mShortcutTargetActivity.finish());
+        }
+
+        // Rollback default shortcut states.
+        if (configureShortcut(ACCESSIBILITY_SHORTCUT_KEY, mA11yShortcutTargets)) {
+            waitForShortcutStateChange(ACCESSIBILITY_SHORTCUT_KEY, mA11yShortcutTargetList);
+        }
+        if (configureShortcut(ACCESSIBILITY_BUTTON, mA11yButtonTargets)) {
+            waitForShortcutStateChange(ACCESSIBILITY_BUTTON, mA11yButtonTargetList);
+        }
+    }
+
+    @Test
+    public void performAccessibilityShortcut_withoutPermission_throwsSecurityException() {
+        try {
+            mAccessibilityManager.performAccessibilityShortcut();
+            fail("No security exception thrown when performing shortcut without permission");
+        } catch (SecurityException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void performAccessibilityShortcut_launchAccessibilityService() {
+        configureShortcut(ACCESSIBILITY_SHORTCUT_KEY, mSpeakingA11yServiceName);
+        waitForShortcutStateChange(ACCESSIBILITY_SHORTCUT_KEY,
+                Arrays.asList(mSpeakingA11yServiceName));
+
+        runWithShellPermissionIdentity(sUiAutomation,
+                () -> mAccessibilityManager.performAccessibilityShortcut());
+
+        // Make sure the service starts up
+        final SpeakingAccessibilityService service = mServiceRule.getService();
+        assertTrue("Speaking accessibility service starts up", service != null);
+    }
+
+    @Test
+    public void performAccessibilityShortcut_launchShortcutTargetActivity() {
+        configureShortcut(ACCESSIBILITY_SHORTCUT_KEY, mShortcutTargetActivityName);
+        waitForShortcutStateChange(ACCESSIBILITY_SHORTCUT_KEY,
+                Arrays.asList(mShortcutTargetActivityName));
+
+        runWithShellPermissionIdentity(sUiAutomation,
+                () -> mAccessibilityManager.performAccessibilityShortcut());
+
+        // Make sure the activity starts up
+        mShortcutTargetActivity = mActivityMonitor.waitForActivityWithTimeout(
+                TIMEOUT_SERVICE_ENABLE);
+        assertTrue("Accessibility shortcut target starts up",
+                mShortcutTargetActivity != null);
+    }
+
+    @Test
+    public void performAccessibilityShortcut_withReqA11yButtonService_a11yButtonCallback() {
+        mA11yButtonServiceRule.enableService();
+        configureShortcut(ACCESSIBILITY_SHORTCUT_KEY, mA11yButtonServiceName);
+        waitForShortcutStateChange(ACCESSIBILITY_SHORTCUT_KEY,
+                Arrays.asList(mA11yButtonServiceName));
+
+        performShortcutAndWaitForA11yButtonClicked(mA11yButtonServiceRule.getService());
+    }
+
+    @Test
+    public void getAccessibilityShortcut_withoutPermission_throwsSecurityException() {
+        try {
+            mAccessibilityManager.getAccessibilityShortcutTargets(ACCESSIBILITY_BUTTON);
+            fail("No security exception thrown when get shortcut without permission");
+        } catch (SecurityException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void getAccessibilityShortcut_assignedShortcutTarget_returnAssignedTarget() {
+        configureShortcut(ACCESSIBILITY_BUTTON, mSpeakingA11yServiceName);
+        waitForShortcutStateChange(ACCESSIBILITY_BUTTON, Arrays.asList(mSpeakingA11yServiceName));
+    }
+
+    @Test
+    public void getAccessibilityShortcut_multipleTargets_returnMultipleTargets() {
+        configureShortcut(ACCESSIBILITY_BUTTON,
+                mSpeakingA11yServiceName, mShortcutTargetActivityName);
+        waitForShortcutStateChange(ACCESSIBILITY_BUTTON,
+                Arrays.asList(mSpeakingA11yServiceName, mShortcutTargetActivityName));
+    }
+
+    /**
+     * Reads current shortcut states.
+     */
+    private void readShortcutStates() {
+        mA11yShortcutTargets = getComponentIdArray(Settings.Secure.getString(mContentResolver,
+                ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
+        mA11yButtonTargets = getComponentIdArray(Settings.Secure.getString(mContentResolver,
+                ACCESSIBILITY_BUTTON_TARGET_COMPONENT));
+        runWithShellPermissionIdentity(sUiAutomation, () -> {
+            mA11yShortcutTargetList = mAccessibilityManager
+                    .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY);
+            mA11yButtonTargetList = mAccessibilityManager
+                    .getAccessibilityShortcutTargets(ACCESSIBILITY_BUTTON);
+        });
+    }
+
+    /**
+     * Returns an array of component names by given colon-separated component name string.
+     *
+     * @param componentIds The colon-separated component name string.
+     * @return The array of component names.
+     */
+    @NonNull
+    private String[] getComponentIdArray(String componentIds) {
+        final List<String> nameList = getComponentIdList(componentIds);
+        if (nameList.isEmpty()) {
+            return EMPTY_STRING_ARRAY;
+        }
+        final String[] result = new String[nameList.size()];
+        return nameList.toArray(result);
+    }
+
+    /**
+     * Return a list of component names by given colon-separated component name string.
+     *
+     * @param componentIds The colon-separated component name string.
+     * @return The list.
+     */
+    @NonNull
+    private List<String> getComponentIdList(String componentIds) {
+        final ArrayList<String> componentIdList = new ArrayList<>();
+        if (TextUtils.isEmpty(componentIds)) {
+            return componentIdList;
+        }
+
+        final TextUtils.SimpleStringSplitter splitter =
+                new TextUtils.SimpleStringSplitter(DELIMITER);
+        splitter.setString(componentIds);
+        for (String name : splitter) {
+            if (TextUtils.isEmpty(name)) {
+                continue;
+            }
+            componentIdList.add(name);
+        }
+        return componentIdList;
+    }
+
+    /**
+     * Return a colon-separated component name string by given string array.
+     *
+     * @param componentIds The array of component names.
+     * @return A colon-separated component name string.
+     */
+    @Nullable
+    private String getComponentIdString(String ... componentIds) {
+        final StringBuilder stringBuilder = new StringBuilder();
+        for (String componentId : componentIds) {
+            if (TextUtils.isEmpty(componentId)) {
+                continue;
+            }
+            if (stringBuilder.length() != 0) {
+                stringBuilder.append(DELIMITER);
+            }
+            stringBuilder.append(componentId);
+        }
+
+        if (stringBuilder.length() == 0) {
+            return null;
+        }
+        return stringBuilder.toString();
+    }
+
+    /**
+     * Update the shortcut settings.
+     *
+     * @param shortcutType The shortcut type.
+     * @param newUseShortcutList The component names which use the shortcut.
+     * @return true if the new states updated.
+     */
+    private boolean configureShortcut(int shortcutType, String ... newUseShortcutList) {
+        final String useShortcutList = getComponentIdString(newUseShortcutList);
+        if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+            return updateAccessibilityShortcut(useShortcutList);
+        } else {
+            return updateAccessibilityButton(useShortcutList);
+        }
+    }
+
+    /**
+     * Update the setting keys of the accessibility shortcut.
+     *
+     * @param newUseShortcutList The value of ACCESSIBILITY_SHORTCUT_TARGET_SERVICE
+     * @return true if the new states updated.
+     */
+    private boolean updateAccessibilityShortcut(String newUseShortcutList) {
+        final ShellCommandBuilder command = ShellCommandBuilder.create(sUiAutomation);
+        final String useShortcutList = Settings.Secure.getString(mContentResolver,
+                ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
+        boolean changes = false;
+        if (!TextUtils.equals(useShortcutList, newUseShortcutList)) {
+            if (TextUtils.isEmpty(newUseShortcutList)) {
+                command.deleteSecureSetting(ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
+            } else {
+                command.putSecureSetting(ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, newUseShortcutList);
+            }
+            changes = true;
+        }
+        if (changes) {
+            command.run();
+        }
+        return changes;
+    }
+
+    /**
+     * Update the setting keys of the accessibility button.
+     *
+     * @param newUseShortcutList The value of ACCESSIBILITY_BUTTON_TARGET_COMPONENT
+     * @return true if the new states updated.
+     */
+    private boolean updateAccessibilityButton(String newUseShortcutList) {
+        final ShellCommandBuilder command = ShellCommandBuilder.create(sUiAutomation);
+        final String useShortcutList = Settings.Secure.getString(mContentResolver,
+                ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
+        boolean changes = false;
+        if (!TextUtils.equals(useShortcutList, newUseShortcutList)) {
+            if (TextUtils.isEmpty(newUseShortcutList)) {
+                command.deleteSecureSetting(ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
+            } else {
+                command.putSecureSetting(ACCESSIBILITY_BUTTON_TARGET_COMPONENT, newUseShortcutList);
+            }
+            changes = true;
+        }
+        if (changes) {
+            command.run();
+        }
+        return changes;
+    }
+
+    /**
+     * Waits for the shortcut state changed, and gets current shortcut list is the same with
+     * expected one.
+     *
+     * @param shortcutType The shortcut type.
+     * @param expectedList The expected shortcut targets returned from
+     *        {@link AccessibilityManager#getAccessibilityShortcutTargets(int)}.
+     */
+    private void waitForShortcutStateChange(int shortcutType, List<String> expectedList) {
+        final StringBuilder message = new StringBuilder();
+        if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+            message.append("Accessibility Shortcut, ");
+        } else {
+            message.append("Accessibility Button, ");
+        }
+        message.append("expect:").append(expectedList);
+        runWithShellPermissionIdentity(sUiAutomation, () ->
+                waitForConditionWithServiceStateChange(mTargetContext, () -> {
+                    final List<String> currentShortcuts =
+                            mAccessibilityManager.getAccessibilityShortcutTargets(shortcutType);
+                    if (currentShortcuts.size() != expectedList.size()) {
+                        return false;
+                    }
+                    for (String expect : expectedList) {
+                        if (!currentShortcuts.contains(expect)) {
+                            return false;
+                        }
+                    }
+                    return true;
+                }, TIMEOUT_SERVICE_ENABLE, message.toString()));
+    }
+
+    /**
+     * Perform shortcut and wait for accessibility button clicked call back.
+     *
+     * @param service The accessibility service
+     */
+    private void performShortcutAndWaitForA11yButtonClicked(AccessibilityService service) {
+        final AtomicBoolean clicked = new AtomicBoolean();
+        final AccessibilityButtonCallback callback = new AccessibilityButtonCallback() {
+            @Override
+            public void onClicked(AccessibilityButtonController controller) {
+                synchronized (clicked) {
+                    clicked.set(true);
+                    clicked.notifyAll();
+                }
+            }
+
+            @Override
+            public void onAvailabilityChanged(AccessibilityButtonController controller,
+                    boolean available) {
+                /* do nothing */
+            }
+        };
+        try {
+            service.getAccessibilityButtonController()
+                    .registerAccessibilityButtonCallback(callback);
+            runWithShellPermissionIdentity(sUiAutomation,
+                    () -> mAccessibilityManager.performAccessibilityShortcut());
+            TestUtils.waitOn(clicked, () -> clicked.get(), TIMEOUT_SERVICE_ENABLE,
+                    "Wait for a11y button clicked");
+        } finally {
+            service.getAccessibilityButtonController()
+                    .unregisterAccessibilityButtonCallback(callback);
+        }
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index f32871b..b37358f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -17,6 +17,7 @@
 package android.accessibilityservice.cts;
 
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventType;
+import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangTypesAndWindowId;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangedWithChangeTypes;
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityOnSpecifiedDisplayAndWaitForItToBeOnscreen;
@@ -768,7 +769,8 @@
         final AccessibilityWindowInfo finalFocusTarget = focusTarget;
         sUiAutomation.executeAndWaitForEvent(() -> assertTrue(finalFocusTarget.getRoot()
                 .performAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)),
-                filterWindowsChangedWithChangeTypes(WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED),
+                filterWindowsChangTypesAndWindowId(finalFocusTarget.getId(),
+                        WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED),
                 DEFAULT_TIMEOUT_MS);
 
         windows = sUiAutomation.getWindows();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
index 35ad056..eb5e2b4 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -49,8 +49,12 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.UiAutomation;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -254,6 +258,26 @@
                             sUiAutomation,
                             AccessibilityEmbeddedDisplayTest.EmbeddedDisplayActivity.class,
                             virtualDisplayId);
+            // Window manager changed the behavior of focused window at a virtual display. A window
+            // at virtual display needs to be touched then it becomes to be focused one. Adding this
+            // touch event on the activity window of the virtual display to pass this test case.
+            final DisplayMetrics displayMetrics = mActivity.getResources().getDisplayMetrics();
+            final int xOnScreen = displayMetrics.widthPixels / 2;
+            final int yOnScreen = displayMetrics.heightPixels / 2;
+            final long downEventTime = SystemClock.uptimeMillis();
+            final MotionEvent downEvent = MotionEvent.obtain(downEventTime, downEventTime,
+                    MotionEvent.ACTION_DOWN, xOnScreen, yOnScreen, 0);
+            downEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+            downEvent.setDisplayId(virtualDisplayId);
+            sUiAutomation.injectInputEvent(downEvent, true);
+
+            final long upEventTime = downEventTime + 10;
+            final MotionEvent upEvent = MotionEvent.obtain(downEventTime, upEventTime,
+                    MotionEvent.ACTION_UP, xOnScreen, yOnScreen, 0);
+            upEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+            upEvent.setDisplayId(virtualDisplayId);
+            sUiAutomation.injectInputEvent(upEvent, true);
+
             final CharSequence activityTitle = getActivityTitle(sInstrumentation,
                     activityOnVirtualDisplay);
             // Make sure activityWindow on virtual display is focused.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
index 790246e..0fd9477 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
@@ -59,6 +59,13 @@
                 new WindowTitleMatcher(uiAutomation, title))::matches;
     }
 
+    public static AccessibilityEventFilter filterWindowsChangTypesAndWindowId(int windowId,
+            int changeTypes) {
+        return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
+                new WindowChangesMatcher(changeTypes),
+                new WindowIdMatcher(windowId))::matches;
+    }
+
     public static class AccessibilityEventTypeMatcher extends TypeSafeMatcher<AccessibilityEvent> {
         private int mType;
 
@@ -167,4 +174,23 @@
             description.appendText("With window title " + mTitle);
         }
     }
+
+    public static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private int mWindowId;
+
+        public WindowIdMatcher(int windowId) {
+            super();
+            mWindowId = windowId;
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getWindowId() == mWindowId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("With window Id " + mWindowId);
+        }
+    }
 }
diff --git a/tests/app/NotificationDelegator/src/com/android/test/notificationdelegator/NotificationRevoker.java b/tests/app/NotificationDelegator/src/com/android/test/notificationdelegator/NotificationRevoker.java
index b2b106e..750549a 100644
--- a/tests/app/NotificationDelegator/src/com/android/test/notificationdelegator/NotificationRevoker.java
+++ b/tests/app/NotificationDelegator/src/com/android/test/notificationdelegator/NotificationRevoker.java
@@ -32,6 +32,7 @@
         NotificationManager nm = getSystemService(NotificationManager.class);
         nm.setNotificationDelegate(null);
         Log.d(TAG, "Removed delegate: " + nm.getNotificationDelegate());
+        nm.cancelAll();
         finish();
     }
 }
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 7434354..ac50181 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -1947,6 +1947,11 @@
                 WAITFOR_MSEC);
         uid3Listener.register();
 
+        UidImportanceListener uid3ServiceListener = new UidImportanceListener(mContext,
+                app3Info.uid, IMPORTANCE_CACHED,
+                WAITFOR_MSEC);
+        uid3ServiceListener.register();
+
         Activity activity = null;
 
         try {
@@ -2014,7 +2019,8 @@
             uid2ServiceListener.waitForValue(
                     IMPORTANCE_CACHED,
                     IMPORTANCE_CACHED);
-            uid3Listener.waitForValue(
+
+            uid3ServiceListener.waitForValue(
                     IMPORTANCE_CACHED,
                     IMPORTANCE_CACHED);
         } finally {
@@ -2031,6 +2037,7 @@
             uid2Listener.unregister();
             uid2ServiceListener.unregister();
             uid3Listener.unregister();
+            uid3ServiceListener.unregister();
             if (activity != null) {
                 activity.finish();
             }
diff --git a/tests/appsearch/OWNERS b/tests/appsearch/OWNERS
new file mode 100644
index 0000000..cf3ad8a
--- /dev/null
+++ b/tests/appsearch/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 755061
+adorokhine@google.com
diff --git a/tests/autofillservice/res/layout/list_item_cancel.xml b/tests/autofillservice/res/layout/list_item_cancel.xml
index 4a3c7d8..e9863e7 100644
--- a/tests/autofillservice/res/layout/list_item_cancel.xml
+++ b/tests/autofillservice/res/layout/list_item_cancel.xml
@@ -30,7 +30,7 @@
         android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
 
     <Button
-        android:id="@+id/cancel"
+        android:id="@+id/cancel_fill"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index ecdf90a..a5ac282 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -53,7 +53,6 @@
 import org.junit.Rule;
 import org.junit.rules.RuleChain;
 import org.junit.rules.TestRule;
-import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
 import org.junit.runner.RunWith;
 import org.junit.runners.model.Statement;
@@ -199,9 +198,15 @@
         protected static final RequiredFeatureRule sRequiredFeatureRule =
                 new RequiredFeatureRule(PackageManager.FEATURE_AUTOFILL);
 
-        private final TestWatcher mTestWatcher = new AutofillTestWatcher();
+        private final AutofillTestWatcher mTestWatcher = new AutofillTestWatcher();
 
-        private final RetryRule mRetryRule = new RetryRule(getNumberRetries());
+        private final RetryRule mRetryRule =
+                new RetryRule(getNumberRetries(), () -> {
+                    // Between testing and retries, clean all launched activities to avoid
+                    // exception:
+                    //     Could not launch intent Intent { ... } within 45 seconds.
+                    mTestWatcher.cleanAllActivities();
+                });
 
         private final AutofillLoggingTestRule mLoggingRule = new AutofillLoggingTestRule(TAG);
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java
index 6879a8c..6c29197 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java
@@ -36,6 +36,18 @@
  */
 public final class AutofillTestWatcher extends TestWatcher {
 
+    /**
+     * Cleans up all launched activities between the tests and retries.
+     */
+    public void cleanAllActivities() {
+        try {
+            finishActivities();
+            waitUntilAllDestroyed();
+        } finally {
+            resetStaticState();
+        }
+    }
+
     private static final String TAG = "AutofillTestWatcher";
 
     @GuardedBy("sUnfinishedBusiness")
@@ -55,12 +67,7 @@
     @Override
     protected void finished(Description description) {
         final String testName = description.getDisplayName();
-        try {
-            finishActivities();
-            waitUntilAllDestroyed();
-        } finally {
-            resetStaticState();
-        }
+        cleanAllActivities();
         Log.i(TAG, "Finished " + testName);
         TestNameUtils.setCurrentTestName(null);
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 4684924..74f9fd9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -98,7 +98,7 @@
     public static final String ID_OUTPUT = "output";
     public static final String ID_STATIC_TEXT = "static_text";
     public static final String ID_EMPTY = "empty";
-    public static final String ID_CANCEL = "cancel";
+    public static final String ID_CANCEL_FILL = "cancel_fill";
 
     public static final String NULL_DATASET_ID = null;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 1ab1b06..165d0b0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -20,7 +20,7 @@
 import static android.autofillservice.cts.CannedFillResponse.FAIL;
 import static android.autofillservice.cts.CannedFillResponse.NO_MOAR_RESPONSES;
 import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
-import static android.autofillservice.cts.Helper.ID_CANCEL;
+import static android.autofillservice.cts.Helper.ID_CANCEL_FILL;
 import static android.autofillservice.cts.Helper.ID_EMPTY;
 import static android.autofillservice.cts.Helper.ID_PASSWORD;
 import static android.autofillservice.cts.Helper.ID_PASSWORD_LABEL;
@@ -2839,7 +2839,7 @@
                         .setField(ID_PASSWORD, "sweet")
                         .setPresentation(createPresentationWithCancel("The Dude"))
                         .build())
-                .setCancelTargetIds(new int[]{R.id.cancel});
+                .setCancelTargetIds(new int[]{R.id.cancel_fill});
         sReplier.addResponse(builder.build());
 
         // Trigger auto-fill.
@@ -2848,8 +2848,8 @@
 
         mUiBot.assertDatasetsContains("The Dude");
 
-        // Tap cancel button
-        mUiBot.selectByRelativeId(ID_CANCEL);
+        // Tap cancel button on fill UI
+        mUiBot.selectByRelativeId(ID_CANCEL_FILL);
         mUiBot.waitForIdle();
 
         mUiBot.assertNoDatasets();
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index 083359a..df9e106 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -50,9 +50,9 @@
 	androidx.test.rules
 
 LOCAL_SRC_FILES := \
-	src/android/hardware/camera2/cts/testcases/Camera2AndroidBasicTestCase.java \
+	src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java \
 	src/android/hardware/camera2/cts/PerformanceTest.java \
-	src/android/hardware/cts/CameraTestCase.java \
+	src/android/hardware/cts/CameraPerformanceTestHelper.java \
 	src/android/hardware/cts/LegacyCameraPerformanceTest.java
 
 LOCAL_SDK_VERSION := test_current
diff --git a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
index 6616942..cfe1db3 100644
--- a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
@@ -26,7 +26,7 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
 import android.util.Log;
@@ -104,9 +104,9 @@
                     continue;
                 }
 
-                CapabilityAndMaxSize[] bokehCaps = staticInfo.getAvailableBokehCapsChecked();
+                Capability[] bokehCaps = staticInfo.getAvailableBokehCapsChecked();
                 boolean supportStillBokeh = false;
-                for (CapabilityAndMaxSize bokehCap : bokehCaps) {
+                for (Capability bokehCap : bokehCaps) {
                     if (bokehCap.getMode() == CameraMetadata.CONTROL_BOKEH_MODE_STILL_CAPTURE) {
                         supportStillBokeh = true;
                         break;
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 35c7da6..961e7c6 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -33,7 +33,7 @@
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.hardware.camera2.params.BlackLevelPattern;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
 import android.hardware.camera2.params.ColorSpaceTransform;
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.LensShadingMap;
@@ -823,6 +823,27 @@
     }
 
     /**
+     * Test zoom using CONTROL_ZOOM_RATIO, validate the returned crop regions and zoom ratio.
+     * The max preview size is used for each camera.
+     */
+    @Test
+    public void testZoomRatio() throws Exception {
+        for (String id : mCameraIdsUnderTest) {
+            try {
+                if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
+                openDevice(id);
+                Size maxPreviewSize = mOrderedPreviewSizes.get(0);
+                zoomRatioTestByCamera(maxPreviewSize);
+            } finally {
+                closeDevice();
+            }
+        }
+    }
+
+    /**
      * Test digital zoom and all preview size combinations.
      * TODO: this and above test should all be moved to preview test class.
      */
@@ -2589,6 +2610,8 @@
         }
 
         final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
+        final Rect defaultCropRegion = new Rect(0, 0,
+                activeArraySize.width(), activeArraySize.height());
         Rect[] cropRegions = new Rect[ZOOM_STEPS];
         MeteringRectangle[][] expectRegions = new MeteringRectangle[ZOOM_STEPS][];
         CaptureRequest.Builder requestBuilder =
@@ -2634,7 +2657,8 @@
                  * Submit capture request
                  */
                 float zoomFactor = (float) (1.0f + (maxZoom - 1.0) * i / ZOOM_STEPS);
-                cropRegions[i] = getCropRegionForZoom(zoomFactor, center, maxZoom, activeArraySize);
+                cropRegions[i] = getCropRegionForZoom(zoomFactor, center,
+                        maxZoom, defaultCropRegion);
                 if (VERBOSE) {
                     Log.v(TAG, "Testing Zoom for factor " + zoomFactor + " and center " +
                             center + " The cropRegion is " + cropRegions[i] +
@@ -2695,7 +2719,7 @@
 
                 // Verify Output 3A region is intersection of input 3A region and crop region
                 for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
-                    validate3aRegion(result, algo, expectRegions[i]);
+                    validate3aRegion(result, algo, expectRegions[i], false/*scaleByZoomRatio*/);
                 }
 
                 previousCrop = cropRegion;
@@ -2713,6 +2737,120 @@
         }
     }
 
+    private void zoomRatioTestByCamera(Size previewSize) throws Exception {
+        final int ZOOM_STEPS = 15;
+        final Range<Float> zoomRatioRange = mStaticInfo.getZoomRatioRangeChecked();
+        // The error margin is derive from a VGA size camera zoomed all the way to 10x, in which
+        // case the cropping error can be as large as 480/46 - 480/48 = 0.435.
+        final float ZOOM_ERROR_MARGIN = 0.05f;
+
+        final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
+        final Rect defaultCropRegion =
+                new Rect(0, 0, activeArraySize.width(), activeArraySize.height());
+        MeteringRectangle[][] expectRegions = new MeteringRectangle[ZOOM_STEPS][];
+        CaptureRequest.Builder requestBuilder =
+                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+        requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, defaultCropRegion);
+        SimpleCaptureCallback listener = new SimpleCaptureCallback();
+
+        updatePreviewSurface(previewSize);
+        configurePreviewOutput(requestBuilder);
+
+        // Set algorithm regions to full active region
+        final MeteringRectangle[] defaultMeteringRect = new MeteringRectangle[] {
+                new MeteringRectangle (
+                        /*x*/0, /*y*/0, activeArraySize.width(), activeArraySize.height(),
+                        /*meteringWeight*/1)
+        };
+
+        for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
+            update3aRegion(requestBuilder, algo,  defaultMeteringRect);
+        }
+
+        final int captureSubmitRepeat;
+        {
+            int maxLatency = mStaticInfo.getSyncMaxLatency();
+            if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) {
+                captureSubmitRepeat = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY + 1;
+            } else {
+                captureSubmitRepeat = maxLatency + 1;
+            }
+        }
+
+        float previousRatio = zoomRatioRange.getLower();
+        for (int i = 0; i < ZOOM_STEPS; i++) {
+            /*
+             * Submit capture request
+             */
+            float zoomFactor = zoomRatioRange.getLower() + (zoomRatioRange.getUpper() -
+                    zoomRatioRange.getLower()) * i / ZOOM_STEPS;
+            if (VERBOSE) {
+                Log.v(TAG, "Testing Zoom ratio " + zoomFactor + " Preview size is " + previewSize);
+            }
+            requestBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, zoomFactor);
+            CaptureRequest request = requestBuilder.build();
+            for (int j = 0; j < captureSubmitRepeat; ++j) {
+                mSession.capture(request, listener, mHandler);
+            }
+
+            /*
+             * Validate capture result
+             */
+            waitForNumResults(listener, captureSubmitRepeat - 1); // Drop first few frames
+            CaptureResult result = listener.getCaptureResultForRequest(
+                    request, NUM_RESULTS_WAIT_TIMEOUT);
+            float resultZoomRatio = getValueNotNull(result, CaptureResult.CONTROL_ZOOM_RATIO);
+            Rect cropRegion = getValueNotNull(result, CaptureResult.SCALER_CROP_REGION);
+
+            /*
+             * Validate resulting crop regions and zoom ratio
+             */
+            mCollector.expectTrue(String.format(
+                    "Zoom ratio should increase or stay the same " +
+                            "(previous = %f, current = %f)",
+                            previousRatio, resultZoomRatio),
+                    Math.abs(previousRatio - resultZoomRatio) < ZOOM_ERROR_MARGIN ||
+                        (previousRatio < resultZoomRatio));
+
+            mCollector.expectTrue(String.format(
+                    "Request and result zoom ratio should be similar " +
+                    "(requested = %f, result = %f", zoomFactor, resultZoomRatio),
+                    Math.abs(zoomFactor - resultZoomRatio)/zoomFactor <= ZOOM_ERROR_MARGIN);
+
+            //In case zoom ratio is converted to crop region at HAL, due to error magnification
+            //when converting to post-zoom crop region, scale the error threshold for crop region
+            //check.
+            float errorMultiplier = Math.max(1.0f, zoomFactor);
+            if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
+                mCollector.expectRectsAreSimilar(
+                        "Request and result crop region should be similar",
+                        activeArraySize, cropRegion,
+                        CROP_REGION_ERROR_PERCENT_DELTA * errorMultiplier);
+            }
+
+            mCollector.expectRectCentered(
+                    "Result crop region should be centered inside the active array",
+                    new Size(activeArraySize.width(), activeArraySize.height()),
+                    cropRegion, CROP_REGION_ERROR_PERCENT_CENTERED * errorMultiplier);
+
+            /*
+             * Validate resulting metering regions
+             */
+            // Use the actual reported crop region to calculate the resulting metering region
+            expectRegions[i] = getExpectedOutputRegion(
+                    /*requestRegion*/defaultMeteringRect,
+                    /*cropRect*/     cropRegion);
+
+            // Verify Output 3A region is intersection of input 3A region and crop region
+            boolean scaleByZoomRatio = zoomFactor > 1.0f;
+            for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
+                validate3aRegion(result, algo, expectRegions[i], scaleByZoomRatio);
+            }
+
+            previousRatio = resultZoomRatio;
+        }
+    }
+
     private void digitalZoomPreviewCombinationTestByCamera() throws Exception {
         final double ASPECT_RATIO_THRESHOLD = 0.001;
         List<Double> aspectRatiosTested = new ArrayList<Double>();
@@ -2798,7 +2936,7 @@
     }
 
     private void bokehModeTestByCamera(List<Range<Integer>> fpsRanges) throws Exception {
-        CapabilityAndMaxSize[] bokehCaps = mStaticInfo.getAvailableBokehCapsChecked();
+        Capability[] bokehCaps = mStaticInfo.getAvailableBokehCapsChecked();
         if (bokehCaps.length == 0) {
             return;
         }
@@ -2807,7 +2945,7 @@
         CaptureRequest.Builder requestBuilder =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
 
-        for (CapabilityAndMaxSize bokehCap : bokehCaps) {
+        for (Capability bokehCap : bokehCaps) {
             int mode = bokehCap.getMode();
             requestBuilder.set(CaptureRequest.CONTROL_BOKEH_MODE, mode);
 
@@ -2817,13 +2955,19 @@
                 verifyFpsNotSlowDown(requestBuilder, NUM_FRAMES_VERIFIED, fpsRanges);
             }
 
-            SimpleCaptureCallback listener = new SimpleCaptureCallback();
-            startPreview(requestBuilder, maxPreviewSize, listener);
-            mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
-            waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+            Range<Float> zoomRange = bokehCap.getZoomRatioRange();
+            float[] zoomRatios = new float[]{zoomRange.getLower(), zoomRange.getUpper()};
+            for (float ratio : zoomRatios) {
+                SimpleCaptureCallback listener = new SimpleCaptureCallback();
+                requestBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, ratio);
+                startPreview(requestBuilder, maxPreviewSize, listener);
+                waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
 
-            verifyCaptureResultForKey(CaptureResult.CONTROL_BOKEH_MODE,
-                    mode, listener, NUM_FRAMES_VERIFIED);
+                verifyCaptureResultForKey(CaptureResult.CONTROL_BOKEH_MODE,
+                        mode, listener, NUM_FRAMES_VERIFIED);
+                verifyCaptureResultForKey(CaptureResult.CONTROL_ZOOM_RATIO,
+                        ratio, listener, NUM_FRAMES_VERIFIED);
+            }
         }
     }
 
@@ -3241,7 +3385,8 @@
      * @param expectRegions The 3A regions expected in capture result
      */
     private void validate3aRegion(
-            CaptureResult result, int algoIdx, MeteringRectangle[] expectRegions)
+            CaptureResult result, int algoIdx, MeteringRectangle[] expectRegions,
+            boolean scaleByZoomRatio)
     {
         final int maxCorrectionDist = 2;
         int maxRegions;
@@ -3269,30 +3414,35 @@
         boolean correctionEnabled =
                 distortionCorrectionMode != null &&
                 distortionCorrectionMode != CaptureResult.DISTORTION_CORRECTION_MODE_OFF;
+        Float zoomRatio = result.get(CaptureResult.CONTROL_ZOOM_RATIO);
+        int maxDist = correctionEnabled ? maxCorrectionDist : 1;
+        if (scaleByZoomRatio) {
+            maxDist = (int)Math.ceil(maxDist * zoomRatio);
+        }
 
         if (maxRegions > 0)
         {
             actualRegion = getValueNotNull(result, key);
-            if (correctionEnabled) {
+            if (correctionEnabled || scaleByZoomRatio) {
                 for(int i = 0; i < actualRegion.length; i++) {
                     Rect a = actualRegion[i].getRect();
                     Rect e = expectRegions[i].getRect();
                     if (!mCollector.expectLessOrEqual(
                         "Expected 3A regions: " + Arrays.toString(expectRegions) +
                         " are not close enough to the actual one: " + Arrays.toString(actualRegion),
-                        maxCorrectionDist, Math.abs(a.left - e.left))) continue;
+                        maxDist, Math.abs(a.left - e.left))) continue;
                     if (!mCollector.expectLessOrEqual(
                         "Expected 3A regions: " + Arrays.toString(expectRegions) +
                         " are not close enough to the actual one: " + Arrays.toString(actualRegion),
-                        maxCorrectionDist, Math.abs(a.right - e.right))) continue;
+                        maxDist, Math.abs(a.right - e.right))) continue;
                     if (!mCollector.expectLessOrEqual(
                         "Expected 3A regions: " + Arrays.toString(expectRegions) +
                         " are not close enough to the actual one: " + Arrays.toString(actualRegion),
-                        maxCorrectionDist, Math.abs(a.top - e.top))) continue;
+                        maxDist, Math.abs(a.top - e.top))) continue;
                     if (!mCollector.expectLessOrEqual(
                         "Expected 3A regions: " + Arrays.toString(expectRegions) +
                         " are not close enough to the actual one: " + Arrays.toString(actualRegion),
-                        maxCorrectionDist, Math.abs(a.bottom - e.bottom))) continue;
+                        maxDist, Math.abs(a.bottom - e.bottom))) continue;
                 }
             } else {
                 mCollector.expectEquals(
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index 247308e..da0c32e 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -806,6 +806,7 @@
         waiverKeys.add(CaptureResult.CONTROL_AF_MODE);
         waiverKeys.add(CaptureResult.CONTROL_AWB_MODE);
         waiverKeys.add(CaptureResult.CONTROL_AWB_LOCK);
+        waiverKeys.add(CaptureResult.CONTROL_ZOOM_RATIO);
         waiverKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
         waiverKeys.add(CaptureResult.FLASH_MODE);
         waiverKeys.add(CaptureResult.SCALER_CROP_REGION);
@@ -946,6 +947,7 @@
         resultKeys.add(CaptureResult.CONTROL_ENABLE_ZSL);
         resultKeys.add(CaptureResult.CONTROL_AF_SCENE_CHANGE);
         resultKeys.add(CaptureResult.CONTROL_BOKEH_MODE);
+        resultKeys.add(CaptureResult.CONTROL_ZOOM_RATIO);
         resultKeys.add(CaptureResult.EDGE_MODE);
         resultKeys.add(CaptureResult.FLASH_MODE);
         resultKeys.add(CaptureResult.FLASH_STATE);
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 0616433..af254b1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
+import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraAccessException;
@@ -36,7 +37,7 @@
 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
-import android.hardware.camera2.cts.testcases.Camera2AndroidBasicTestCase;
+import android.hardware.camera2.cts.testcases.Camera2AndroidTestRule;
 import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
@@ -59,7 +60,10 @@
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
 
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -71,7 +75,8 @@
  * Test camera2 API use case performance KPIs, such as camera open time, session creation time,
  * shutter lag etc. The KPI data will be reported in cts results.
  */
-public class PerformanceTest extends Camera2AndroidBasicTestCase {
+@RunWith(JUnit4.class)
+public class PerformanceTest {
     private static final String TAG = "PerformanceTest";
     private static final String REPORT_LOG_NAME = "CtsCameraTestCases";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -102,21 +107,15 @@
     private ImageWriter mWriter;
     private SimpleCaptureCallback mZslResultListener;
 
-    private Instrumentation mInstrumentation;
-
     private Surface mPreviewSurface;
     private SurfaceTexture mPreviewSurfaceTexture;
 
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-    }
+    private static final Instrumentation mInstrumentation =
+            InstrumentationRegistry.getInstrumentation();
+    private static final Context mContext = InstrumentationRegistry.getTargetContext();
 
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
+    @Rule
+    public final Camera2AndroidTestRule mTestRule = new Camera2AndroidTestRule(mContext);
 
     /**
      * Test camera launch KPI: the time duration between a camera device is
@@ -132,11 +131,12 @@
      * For depth-only devices, timing is done with the DEPTH16 format instead.
      * </p>
      */
+    @Test
     public void testCameraLaunch() throws Exception {
-        double[] avgCameraLaunchTimes = new double[mCameraIdsUnderTest.length];
+        double[] avgCameraLaunchTimes = new double[mTestRule.getCameraIdsUnderTest().length];
 
         int counter = 0;
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             // Do NOT move these variables to outer scope
             // They will be passed to DeviceReportLog and their references will be stored
             String streamName = "test_camera_launch";
@@ -149,12 +149,13 @@
             double[] cameraCloseTimes = new double[NUM_TEST_LOOPS];
             double[] cameraLaunchTimes = new double[NUM_TEST_LOOPS];
             try {
-                mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(id));
-                if (mStaticInfo.isColorOutputSupported()) {
+                mTestRule.setStaticInfo(new StaticMetadata(
+                        mTestRule.getCameraManager().getCameraCharacteristics(id)));
+                if (mTestRule.getStaticInfo().isColorOutputSupported()) {
                     initializeImageReader(id, ImageFormat.YUV_420_888);
                 } else {
                     assertTrue("Depth output must be supported if regular output isn't!",
-                            mStaticInfo.isDepthOutputSupported());
+                            mTestRule.getStaticInfo().isDepthOutputSupported());
                     initializeImageReader(id, ImageFormat.DEPTH16);
                 }
 
@@ -165,7 +166,8 @@
                         // Need create a new listener every iteration to be able to wait
                         // for the first image comes out.
                         imageListener = new SimpleImageListener();
-                        mReader.setOnImageAvailableListener(imageListener, mHandler);
+                        mTestRule.getReader().setOnImageAvailableListener(
+                                imageListener, mTestRule.getHandler());
                         startTimeMs = SystemClock.elapsedRealtime();
 
                         // Blocking open camera
@@ -198,7 +200,7 @@
                     finally {
                         // Blocking camera close
                         startTimeMs = SystemClock.elapsedRealtime();
-                        closeDevice(id);
+                        mTestRule.closeDevice(id);
                         cameraCloseTimes[i] = SystemClock.elapsedRealtime() - startTimeMs;
                     }
                 }
@@ -220,7 +222,7 @@
                         ResultType.LOWER_BETTER, ResultUnit.MS);
             }
             finally {
-                closeDefaultImageReader();
+                mTestRule.closeDefaultImageReader();
                 closePreviewSurface();
             }
             counter++;
@@ -259,7 +261,7 @@
                         + ". Max(ms): " + Stat.getMax(cameraLaunchTimes));
             }
         }
-        if (mCameraIdsUnderTest.length != 0) {
+        if (mTestRule.getCameraIdsUnderTest().length != 0) {
             String streamName = "test_camera_launch_average";
             mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
             mReportLog.setSummary("camera_launch_average_time_for_all_cameras",
@@ -281,6 +283,7 @@
      * out the capture request and getting the full capture result.
      * </p>
      */
+    @Test
     public void testSingleCapture() throws Exception {
         int[] YUV_FORMAT = {ImageFormat.YUV_420_888};
         testSingleCaptureForFormat(YUV_FORMAT, null, /*addPreviewDelay*/ false);
@@ -309,10 +312,10 @@
 
     private void testSingleCaptureForFormat(int[] formats, String formatDescription,
             boolean addPreviewDelay) throws Exception {
-        double[] avgResultTimes = new double[mCameraIdsUnderTest.length];
+        double[] avgResultTimes = new double[mTestRule.getCameraIdsUnderTest().length];
 
         int counter = 0;
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             // Do NOT move these variables to outer scope
             // They will be passed to DeviceReportLog and their references will be stored
             String streamName = appendFormatDescription("test_single_capture", formatDescription);
@@ -323,12 +326,13 @@
             double[] getResultTimes = new double[NUM_TEST_LOOPS];
             ImageReader[] readers = null;
             try {
-                if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
+                if (!mTestRule.getAllStaticInfo().get(id).isColorOutputSupported()) {
                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
                     continue;
                 }
 
-                StreamConfigurationMap configMap = mAllStaticInfo.get(id).getCharacteristics().get(
+                StreamConfigurationMap configMap = mTestRule.getAllStaticInfo().get(
+                        id).getCharacteristics().get(
                         CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                 boolean formatsSupported = true;
                 for (int format : formats) {
@@ -343,18 +347,20 @@
                     continue;
                 }
 
-                openDevice(id);
+                mTestRule.openDevice(id);
 
-                boolean partialsExpected = mStaticInfo.getPartialResultCount() > 1;
+                boolean partialsExpected = mTestRule.getStaticInfo().getPartialResultCount() > 1;
                 long startTimeMs;
                 boolean isPartialTimingValid = partialsExpected;
                 for (int i = 0; i < NUM_TEST_LOOPS; i++) {
 
                     // setup builders and listeners
                     CaptureRequest.Builder previewBuilder =
-                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+                            mTestRule.getCamera().createCaptureRequest(
+                                    CameraDevice.TEMPLATE_PREVIEW);
                     CaptureRequest.Builder captureBuilder =
-                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+                            mTestRule.getCamera().createCaptureRequest(
+                                    CameraDevice.TEMPLATE_STILL_CAPTURE);
                     SimpleCaptureCallback previewResultListener =
                             new SimpleCaptureCallback();
                     SimpleTimingResultListener captureResultListener =
@@ -363,12 +369,15 @@
                     Size[] imageSizes = new Size[formats.length];
                     for (int j = 0; j < formats.length; j++) {
                         imageSizes[j] = CameraTestUtils.getSortedSizesForFormat(
-                                id, mCameraManager, formats[j], /*bound*/null).get(0);
+                                id,
+                                mTestRule.getCameraManager(),
+                                formats[j],
+                                /*bound*/null).get(0);
                         imageListeners[j] = new SimpleImageListener();
                     }
 
                     readers = prepareStillCaptureAndStartPreview(previewBuilder, captureBuilder,
-                            mOrderedPreviewSizes.get(0), imageSizes, formats,
+                            mTestRule.getOrderedPreviewSizes().get(0), imageSizes, formats,
                             previewResultListener, NUM_MAX_IMAGES, imageListeners,
                             false /*isHeic*/);
 
@@ -379,12 +388,13 @@
                     // Capture an image and get image data
                     startTimeMs = SystemClock.elapsedRealtime();
                     CaptureRequest request = captureBuilder.build();
-                    mCameraSession.capture(request, captureResultListener, mHandler);
+                    mTestRule.getCameraSession().capture(
+                            request, captureResultListener, mTestRule.getHandler());
 
                     Pair<CaptureResult, Long> partialResultNTime = null;
                     if (partialsExpected) {
                         partialResultNTime = captureResultListener.getPartialResultNTimeForRequest(
-                            request, NUM_RESULTS_WAIT);
+                                request, NUM_RESULTS_WAIT);
                         // Even if maxPartials > 1, may not see partials for some devices
                         if (partialResultNTime == null) {
                             partialsExpected = false;
@@ -440,7 +450,7 @@
             finally {
                 CameraTestUtils.closeImageReaders(readers);
                 readers = null;
-                closeDevice(id);
+                mTestRule.closeDevice(id);
                 closePreviewSurface();
             }
             counter++;
@@ -448,7 +458,7 @@
         }
 
         // Result will not be reported in CTS report if no summary is printed.
-        if (mCameraIdsUnderTest.length != 0) {
+        if (mTestRule.getCameraIdsUnderTest().length != 0) {
             String streamName = appendFormatDescription("test_single_capture_average",
                     formatDescription);
             mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
@@ -469,9 +479,10 @@
      * gap between results.
      * </p>
      */
+    @Test
     public void testMultipleCapture() throws Exception {
-        double[] avgResultTimes = new double[mCameraIdsUnderTest.length];
-        double[] avgDurationMs = new double[mCameraIdsUnderTest.length];
+        double[] avgResultTimes = new double[mTestRule.getCameraIdsUnderTest().length];
+        double[] avgDurationMs = new double[mTestRule.getCameraIdsUnderTest().length];
 
         // A simple CaptureSession StateCallback to handle onCaptureQueueEmpty
         class MultipleCaptureStateCallback extends CameraCaptureSession.StateCallback {
@@ -493,7 +504,7 @@
                 captureQueueEmptied++;
                 if (VERBOSE) {
                     Log.v(TAG, "onCaptureQueueEmpty received. captureQueueEmptied = "
-                        + captureQueueEmptied);
+                            + captureQueueEmptied);
                 }
 
                 captureQueueEmptyCond.open();
@@ -512,7 +523,7 @@
                     captureQueueEmptied = 0;
                 } else {
                     throw new TimeoutRuntimeException("Unable to receive onCaptureQueueEmpty after "
-                        + timeout + "ms");
+                            + timeout + "ms");
                 }
             }
         }
@@ -520,7 +531,7 @@
         final MultipleCaptureStateCallback sessionListener = new MultipleCaptureStateCallback();
 
         int counter = 0;
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             // Do NOT move these variables to outer scope
             // They will be passed to DeviceReportLog and their references will be stored
             String streamName = "test_multiple_capture";
@@ -530,19 +541,21 @@
             double[] getResultTimes = new double[NUM_MAX_IMAGES];
             double[] frameDurationMs = new double[NUM_MAX_IMAGES-1];
             try {
-                if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
+                if (!mTestRule.getAllStaticInfo().get(id).isColorOutputSupported()) {
                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
                     continue;
                 }
 
-                openDevice(id);
+                mTestRule.openDevice(id);
                 for (int i = 0; i < NUM_TEST_LOOPS; i++) {
 
                     // setup builders and listeners
                     CaptureRequest.Builder previewBuilder =
-                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+                            mTestRule.getCamera().createCaptureRequest(
+                                    CameraDevice.TEMPLATE_PREVIEW);
                     CaptureRequest.Builder captureBuilder =
-                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+                            mTestRule.getCamera().createCaptureRequest(
+                                    CameraDevice.TEMPLATE_STILL_CAPTURE);
                     SimpleCaptureCallback previewResultListener =
                             new SimpleCaptureCallback();
                     SimpleTimingResultListener captureResultListener =
@@ -551,37 +564,39 @@
                             new SimpleImageReaderListener(/*asyncMode*/true, NUM_MAX_IMAGES);
 
                     Size maxYuvSize = CameraTestUtils.getSortedSizesForFormat(
-                        id, mCameraManager, ImageFormat.YUV_420_888, /*bound*/null).get(0);
+                            id, mTestRule.getCameraManager(),
+                            ImageFormat.YUV_420_888, /*bound*/null).get(0);
                     // Find minimum frame duration for YUV_420_888
-                    StreamConfigurationMap config = mStaticInfo.getCharacteristics().get(
+                    StreamConfigurationMap config =
+                            mTestRule.getStaticInfo().getCharacteristics().get(
                             CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
 
                     final long minStillFrameDuration =
                             config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize);
                     if (minStillFrameDuration > 0) {
                         Range<Integer> targetRange =
-                            CameraTestUtils.getSuitableFpsRangeForDuration(id,
-                                    minStillFrameDuration, mStaticInfo);
+                                CameraTestUtils.getSuitableFpsRangeForDuration(id,
+                                        minStillFrameDuration, mTestRule.getStaticInfo());
                         previewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetRange);
                         captureBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetRange);
                     }
 
                     prepareCaptureAndStartPreview(previewBuilder, captureBuilder,
-                            mOrderedPreviewSizes.get(0), maxYuvSize,
+                            mTestRule.getOrderedPreviewSizes().get(0), maxYuvSize,
                             ImageFormat.YUV_420_888, previewResultListener,
                             sessionListener, NUM_MAX_IMAGES, imageListener);
 
                     // Converge AE
                     CameraTestUtils.waitForAeStable(previewResultListener,
-                            NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY, mStaticInfo,
+                            NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY, mTestRule.getStaticInfo(),
                             WAIT_FOR_RESULT_TIMEOUT_MS, NUM_RESULTS_WAIT_TIMEOUT);
 
-                    if (mStaticInfo.isAeLockSupported()) {
+                    if (mTestRule.getStaticInfo().isAeLockSupported()) {
                         // Lock AE if possible to improve stability
                         previewBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
-                        mCameraSession.setRepeatingRequest(previewBuilder.build(),
-                                previewResultListener, mHandler);
-                        if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
+                        mTestRule.getCameraSession().setRepeatingRequest(previewBuilder.build(),
+                                previewResultListener, mTestRule.getHandler());
+                        if (mTestRule.getStaticInfo().isHardwareLevelAtLeastLimited()) {
                             // Legacy mode doesn't output AE state
                             CameraTestUtils.waitForResultValue(previewResultListener,
                                     CaptureResult.CONTROL_AE_STATE,
@@ -596,7 +611,8 @@
                         // Capture an image and get image data
                         startTimes[j] = SystemClock.elapsedRealtime();
                         CaptureRequest request = captureBuilder.build();
-                        mCameraSession.capture(request, captureResultListener, mHandler);
+                        mTestRule.getCameraSession().capture(
+                                request, captureResultListener, mTestRule.getHandler());
 
                         // Wait for capture queue empty for the current request
                         sessionListener.waitForCaptureQueueEmpty(
@@ -614,10 +630,12 @@
                                 (double)(captureResultNTime.second - startTimes[j])/NUM_TEST_LOOPS;
 
                         // Collect inter-frame timestamp
-                        long timestamp = captureResultNTime.first.get(CaptureResult.SENSOR_TIMESTAMP);
+                        long timestamp = captureResultNTime.first.get(
+                                CaptureResult.SENSOR_TIMESTAMP);
                         if (prevTimestamp != -1) {
                             frameDurationMs[j-1] +=
-                                    (double)(timestamp - prevTimestamp)/(NUM_TEST_LOOPS * 1000000.0);
+                                    (double)(timestamp - prevTimestamp)/(
+                                            NUM_TEST_LOOPS * 1000000.0);
                         }
                         prevTimestamp = timestamp;
                     }
@@ -648,8 +666,8 @@
                 avgDurationMs[counter] = Stat.getAverage(frameDurationMs);
             }
             finally {
-                closeDefaultImageReader();
-                closeDevice(id);
+                mTestRule.closeDefaultImageReader();
+                mTestRule.closeDevice(id);
                 closePreviewSurface();
             }
             counter++;
@@ -657,7 +675,7 @@
         }
 
         // Result will not be reported in CTS report if no summary is printed.
-        if (mCameraIdsUnderTest.length != 0) {
+        if (mTestRule.getCameraIdsUnderTest().length != 0) {
             String streamName = "test_multiple_capture_average";
             mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
             mReportLog.setSummary("camera_multiple_capture_result_average_latency_for_all_cameras",
@@ -674,15 +692,16 @@
      * Test reprocessing shot-to-shot latency with default NR and edge options, i.e., from the time
      * a reprocess request is issued to the time the reprocess image is returned.
      */
+    @Test
     public void testReprocessingLatency() throws Exception {
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             for (int format : REPROCESS_FORMATS) {
                 if (!isReprocessSupported(id, format)) {
                     continue;
                 }
 
                 try {
-                    openDevice(id);
+                    mTestRule.openDevice(id);
                     String streamName = "test_reprocessing_latency";
                     mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
                     mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
@@ -691,7 +710,7 @@
                             /*highQuality*/false);
                 } finally {
                     closeReaderWriters();
-                    closeDevice(id);
+                    mTestRule.closeDevice(id);
                     closePreviewSurface();
                     mReportLog.submit(mInstrumentation);
                 }
@@ -700,19 +719,20 @@
     }
 
     /**
-     * Test reprocessing throughput with default NR and edge options, i.e., how many frames can be reprocessed
-     * during a given amount of time.
+     * Test reprocessing throughput with default NR and edge options,
+     * i.e., how many frames can be reprocessed during a given amount of time.
      *
      */
+    @Test
     public void testReprocessingThroughput() throws Exception {
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             for (int format : REPROCESS_FORMATS) {
                 if (!isReprocessSupported(id, format)) {
                     continue;
                 }
 
                 try {
-                    openDevice(id);
+                    mTestRule.openDevice(id);
                     String streamName = "test_reprocessing_throughput";
                     mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
                     mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
@@ -721,7 +741,7 @@
                             /*highQuality*/false);
                 } finally {
                     closeReaderWriters();
-                    closeDevice(id);
+                    mTestRule.closeDevice(id);
                     closePreviewSurface();
                     mReportLog.submit(mInstrumentation);
                 }
@@ -733,15 +753,16 @@
      * Test reprocessing shot-to-shot latency with High Quality NR and edge options, i.e., from the
      * time a reprocess request is issued to the time the reprocess image is returned.
      */
+    @Test
     public void testHighQualityReprocessingLatency() throws Exception {
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             for (int format : REPROCESS_FORMATS) {
                 if (!isReprocessSupported(id, format)) {
                     continue;
                 }
 
                 try {
-                    openDevice(id);
+                    mTestRule.openDevice(id);
                     String streamName = "test_high_quality_reprocessing_latency";
                     mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
                     mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
@@ -750,7 +771,7 @@
                             /*requireHighQuality*/true);
                 } finally {
                     closeReaderWriters();
-                    closeDevice(id);
+                    mTestRule.closeDevice(id);
                     closePreviewSurface();
                     mReportLog.submit(mInstrumentation);
                 }
@@ -763,15 +784,16 @@
      * be reprocessed during a given amount of time.
      *
      */
+    @Test
     public void testHighQualityReprocessingThroughput() throws Exception {
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             for (int format : REPROCESS_FORMATS) {
                 if (!isReprocessSupported(id, format)) {
                     continue;
                 }
 
                 try {
-                    openDevice(id);
+                    mTestRule.openDevice(id);
                     String streamName = "test_high_quality_reprocessing_throughput";
                     mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
                     mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
@@ -780,7 +802,7 @@
                             /*requireHighQuality*/true);
                 } finally {
                     closeReaderWriters();
-                    closeDevice(id);
+                    mTestRule.closeDevice(id);
                     closePreviewSurface();
                     mReportLog.submit(mInstrumentation);
                 }
@@ -791,15 +813,16 @@
     /**
      * Testing reprocessing caused preview stall (frame drops)
      */
+    @Test
     public void testReprocessingCaptureStall() throws Exception {
-        for (String id : mCameraIdsUnderTest) {
+        for (String id : mTestRule.getCameraIdsUnderTest()) {
             for (int format : REPROCESS_FORMATS) {
                 if (!isReprocessSupported(id, format)) {
                     continue;
                 }
 
                 try {
-                    openDevice(id);
+                    mTestRule.openDevice(id);
                     String streamName = "test_reprocessing_capture_stall";
                     mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
                     mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
@@ -807,7 +830,7 @@
                     reprocessingCaptureStallTestByCamera(format);
                 } finally {
                     closeReaderWriters();
-                    closeDevice(id);
+                    mTestRule.closeDevice(id);
                     closePreviewSurface();
                     mReportLog.submit(mInstrumentation);
                 }
@@ -832,7 +855,7 @@
             TotalCaptureResult zslResult =
                     mZslResultListener.getCaptureResult(
                             WAIT_FOR_RESULT_TIMEOUT_MS, inputImages[i].getTimestamp());
-            reprocessReqs[i] = mCamera.createReprocessCaptureRequest(zslResult);
+            reprocessReqs[i] = mTestRule.getCamera().createReprocessCaptureRequest(zslResult);
             reprocessReqs[i].addTarget(mJpegReader.getSurface());
             reprocessReqs[i].set(CaptureRequest.NOISE_REDUCTION_MODE,
                     CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
@@ -849,14 +872,15 @@
         for (int i = 0; i < NUM_REPROCESS_TESTED; i++) {
             mZslResultListener.drain();
             CaptureRequest reprocessRequest = reprocessReqs[i].build();
-            mCameraSession.capture(reprocessRequest, reprocessResultListener, mHandler);
+            mTestRule.getCameraSession().capture(
+                    reprocessRequest, reprocessResultListener, mTestRule.getHandler());
             // Wait for reprocess output jpeg and result come back.
             reprocessResultListener.getCaptureResultForRequest(reprocessRequest,
                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
             mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS).close();
             long numFramesMaybeStalled = mZslResultListener.getTotalNumFrames();
             assertTrue("Reprocess capture result should be returned in "
-                    + MAX_REPROCESS_RETURN_FRAME_COUNT + " frames",
+                            + MAX_REPROCESS_RETURN_FRAME_COUNT + " frames",
                     numFramesMaybeStalled <= MAX_REPROCESS_RETURN_FRAME_COUNT);
 
             // Need look longer time, as the stutter could happen after the reprocessing
@@ -910,7 +934,7 @@
 
         // The max timestamp gap should be less than (captureStall + 1) x average frame
         // duration * (1 + error margin).
-        int maxCaptureStallFrames = mStaticInfo.getMaxCaptureStallOrDefault();
+        int maxCaptureStallFrames = mTestRule.getStaticInfo().getMaxCaptureStallOrDefault();
         for (int i = 0; i < maxCaptureGapsMs.length; i++) {
             double stallDurationBound = averageFrameDurationMs[i] *
                     (maxCaptureStallFrames + 1) * (1 + REPROCESS_STALL_MARGIN);
@@ -939,7 +963,7 @@
             TotalCaptureResult zslResult =
                     mZslResultListener.getCaptureResult(
                             WAIT_FOR_RESULT_TIMEOUT_MS, inputImages[i].getTimestamp());
-            reprocessReqs[i] = mCamera.createReprocessCaptureRequest(zslResult);
+            reprocessReqs[i] = mTestRule.getCamera().createReprocessCaptureRequest(zslResult);
             if (requireHighQuality) {
                 // Reprocessing should support high quality for NR and edge modes.
                 reprocessReqs[i].set(CaptureRequest.NOISE_REDUCTION_MODE,
@@ -960,7 +984,7 @@
 
             // Submit the requests
             for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
-                mCameraSession.capture(reprocessReqs[i].build(), null, null);
+                mTestRule.getCameraSession().capture(reprocessReqs[i].build(), null, null);
             }
 
             // Get images
@@ -982,7 +1006,7 @@
             for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
                 startTimeMs = SystemClock.elapsedRealtime();
                 mWriter.queueInputImage(inputImages[i]);
-                mCameraSession.capture(reprocessReqs[i].build(), null, null);
+                mTestRule.getCameraSession().capture(reprocessReqs[i].build(), null, null);
                 jpegImages[i] = mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
                 getImageLatenciesMs[i] = SystemClock.elapsedRealtime() - startTimeMs;
             }
@@ -1034,16 +1058,17 @@
      */
     private void startZslStreaming() throws Exception {
         CaptureRequest.Builder zslBuilder =
-                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
+                mTestRule.getCamera().createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
         zslBuilder.addTarget(mPreviewSurface);
         zslBuilder.addTarget(mCameraZslReader.getSurface());
-        mCameraSession.setRepeatingRequest(zslBuilder.build(), mZslResultListener, mHandler);
+        mTestRule.getCameraSession().setRepeatingRequest(
+                zslBuilder.build(), mZslResultListener, mTestRule.getHandler());
     }
 
     private void stopZslStreaming() throws Exception {
-        mCameraSession.stopRepeating();
-        mCameraSessionListener.getStateWaiter().waitForState(
-            BlockingSessionCallback.SESSION_READY, CameraTestUtils.CAMERA_IDLE_TIMEOUT_MS);
+        mTestRule.getCameraSession().stopRepeating();
+        mTestRule.getCameraSessionListener().getStateWaiter().waitForState(
+                BlockingSessionCallback.SESSION_READY, CameraTestUtils.CAMERA_IDLE_TIMEOUT_MS);
     }
 
     /**
@@ -1076,14 +1101,14 @@
     }
 
     private void prepareReprocessCapture(int inputFormat)
-                    throws CameraAccessException {
+            throws CameraAccessException {
         // 1. Find the right preview and capture sizes.
-        Size maxPreviewSize = mOrderedPreviewSizes.get(0);
+        Size maxPreviewSize = mTestRule.getOrderedPreviewSizes().get(0);
         Size[] supportedInputSizes =
-                mStaticInfo.getAvailableSizesForFormatChecked(inputFormat,
-                StaticMetadata.StreamDirection.Input);
+                mTestRule.getStaticInfo().getAvailableSizesForFormatChecked(inputFormat,
+                        StaticMetadata.StreamDirection.Input);
         Size maxInputSize = CameraTestUtils.getMaxSize(supportedInputSizes);
-        Size maxJpegSize = mOrderedStillSizes.get(0);
+        Size maxJpegSize = mTestRule.getOrderedStillSizes().get(0);
         updatePreviewSurface(maxPreviewSize);
         mZslResultListener = new SimpleCaptureCallback();
 
@@ -1092,11 +1117,13 @@
         mCameraZslImageListener = new SimpleImageReaderListener(
                 /*asyncMode*/true, MAX_ZSL_IMAGES - MAX_REPROCESS_IMAGES);
         mCameraZslReader = CameraTestUtils.makeImageReader(
-                maxInputSize, inputFormat, MAX_ZSL_IMAGES, mCameraZslImageListener, mHandler);
+                maxInputSize, inputFormat, MAX_ZSL_IMAGES,
+                mCameraZslImageListener, mTestRule.getHandler());
         // Jpeg reprocess output
         mJpegListener = new SimpleImageReaderListener();
         mJpegReader = CameraTestUtils.makeImageReader(
-                maxJpegSize, ImageFormat.JPEG, MAX_JPEG_IMAGES, mJpegListener, mHandler);
+                maxJpegSize, ImageFormat.JPEG, MAX_JPEG_IMAGES,
+                mJpegListener, mTestRule.getHandler());
 
         // create camera reprocess session
         List<Surface> outSurfaces = new ArrayList<Surface>();
@@ -1105,35 +1132,37 @@
         outSurfaces.add(mJpegReader.getSurface());
         InputConfiguration inputConfig = new InputConfiguration(maxInputSize.getWidth(),
                 maxInputSize.getHeight(), inputFormat);
-        mCameraSessionListener = new BlockingSessionCallback();
-        mCameraSession = CameraTestUtils.configureReprocessableCameraSession(
-                mCamera, inputConfig, outSurfaces, mCameraSessionListener, mHandler);
+        mTestRule.setCameraSessionListener(new BlockingSessionCallback());
+        mTestRule.setCameraSession(CameraTestUtils.configureReprocessableCameraSession(
+                mTestRule.getCamera(), inputConfig, outSurfaces,
+                mTestRule.getCameraSessionListener(), mTestRule.getHandler()));
 
         // 3. Create ImageWriter for input
         mWriter = CameraTestUtils.makeImageWriter(
-                mCameraSession.getInputSurface(), MAX_INPUT_IMAGES, /*listener*/null, /*handler*/null);
-
+                mTestRule.getCameraSession().getInputSurface(), MAX_INPUT_IMAGES,
+                /*listener*/null, /*handler*/null);
     }
 
     private void blockingStopPreview() throws Exception {
         stopPreview();
-        mCameraSessionListener.getStateWaiter().waitForState(SESSION_CLOSED,
-                CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS);
+        mTestRule.getCameraSessionListener().getStateWaiter().waitForState(
+                BlockingSessionCallback.SESSION_CLOSED, CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS);
     }
 
     private void blockingStartPreview(CaptureCallback listener, SimpleImageListener imageListener)
             throws Exception {
-        if (mPreviewSurface == null || mReaderSurface == null) {
+        if (mPreviewSurface == null || mTestRule.getReaderSurface() == null) {
             throw new IllegalStateException("preview and reader surface must be initilized first");
         }
 
         CaptureRequest.Builder previewBuilder =
-                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
-        if (mStaticInfo.isColorOutputSupported()) {
+                mTestRule.getCamera().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+        if (mTestRule.getStaticInfo().isColorOutputSupported()) {
             previewBuilder.addTarget(mPreviewSurface);
         }
-        previewBuilder.addTarget(mReaderSurface);
-        mCameraSession.setRepeatingRequest(previewBuilder.build(), listener, mHandler);
+        previewBuilder.addTarget(mTestRule.getReaderSurface());
+        mTestRule.getCameraSession().setRepeatingRequest(
+                previewBuilder.build(), listener, mTestRule.getHandler());
         imageListener.waitForImageAvailable(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
     }
 
@@ -1176,13 +1205,14 @@
         outputSurfaces.add(mPreviewSurface);
         for (int i = 0; i < captureSizes.length; i++) {
             readers[i] = CameraTestUtils.makeImageReader(captureSizes[i], formats[i], maxNumImages,
-                    imageListeners[i], mHandler);
+                    imageListeners[i], mTestRule.getHandler());
             outputSurfaces.add(readers[i].getSurface());
         }
 
-        mCameraSessionListener = new BlockingSessionCallback();
-        mCameraSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces,
-                mCameraSessionListener, mHandler);
+        mTestRule.setCameraSessionListener(new BlockingSessionCallback());
+        mTestRule.setCameraSession(CameraTestUtils.configureCameraSession(
+                mTestRule.getCamera(), outputSurfaces,
+                mTestRule.getCameraSessionListener(), mTestRule.getHandler()));
 
         // Configure the requests.
         previewRequest.addTarget(mPreviewSurface);
@@ -1192,7 +1222,8 @@
         }
 
         // Start preview.
-        mCameraSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
+        mTestRule.getCameraSession().setRepeatingRequest(
+                previewRequest.build(), resultListener, mTestRule.getHandler());
 
         return readers;
     }
@@ -1227,27 +1258,29 @@
         updatePreviewSurface(previewSz);
 
         // Create ImageReader.
-        createDefaultImageReader(captureSz, format, maxNumImages, imageListener);
+        mTestRule.createDefaultImageReader(captureSz, format, maxNumImages, imageListener);
 
         // Configure output streams with preview and jpeg streams.
         List<Surface> outputSurfaces = new ArrayList<Surface>();
         outputSurfaces.add(mPreviewSurface);
-        outputSurfaces.add(mReaderSurface);
+        outputSurfaces.add(mTestRule.getReaderSurface());
         if (sessionListener == null) {
-            mCameraSessionListener = new BlockingSessionCallback();
+            mTestRule.setCameraSessionListener(new BlockingSessionCallback());
         } else {
-            mCameraSessionListener = new BlockingSessionCallback(sessionListener);
+            mTestRule.setCameraSessionListener(new BlockingSessionCallback(sessionListener));
         }
-        mCameraSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces,
-                mCameraSessionListener, mHandler);
+        mTestRule.setCameraSession(CameraTestUtils.configureCameraSession(
+                mTestRule.getCamera(), outputSurfaces,
+                mTestRule.getCameraSessionListener(), mTestRule.getHandler()));
 
         // Configure the requests.
         previewRequest.addTarget(mPreviewSurface);
         stillRequest.addTarget(mPreviewSurface);
-        stillRequest.addTarget(mReaderSurface);
+        stillRequest.addTarget(mTestRule.getReaderSurface());
 
         // Start preview.
-        mCameraSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
+        mTestRule.getCameraSession().setRepeatingRequest(
+                previewRequest.build(), resultListener, mTestRule.getHandler());
     }
 
     /**
@@ -1288,7 +1321,7 @@
         }
 
         StaticMetadata info = new StaticMetadata(
-                mCameraManager.getCameraCharacteristics(cameraId), CheckLevel.ASSERT,
+                mTestRule.getCameraManager().getCameraCharacteristics(cameraId), CheckLevel.ASSERT,
                 /*collector*/ null);
         int cap = CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING;
         if (format == ImageFormat.PRIVATE) {
@@ -1303,9 +1336,9 @@
      */
     private void stopPreview() throws Exception {
         // Stop repeat, wait for captures to complete, and disconnect from surfaces
-        if (mCameraSession != null) {
+        if (mTestRule.getCameraSession() != null) {
             if (VERBOSE) Log.v(TAG, "Stopping preview");
-            mCameraSession.close();
+            mTestRule.getCameraSession().close();
         }
     }
 
@@ -1315,10 +1348,10 @@
      */
     private void stopPreviewAndDrain() throws Exception {
         // Stop repeat, wait for captures to complete, and disconnect from surfaces
-        if (mCameraSession != null) {
+        if (mTestRule.getCameraSession() != null) {
             if (VERBOSE) Log.v(TAG, "Stopping preview and waiting for idle");
-            mCameraSession.close();
-            mCameraSessionListener.getStateWaiter().waitForState(
+            mTestRule.getCameraSession().close();
+            mTestRule.getCameraSessionListener().getStateWaiter().waitForState(
                     BlockingSessionCallback.SESSION_CLOSED,
                     /*timeoutMs*/WAIT_FOR_RESULT_TIMEOUT_MS);
         }
@@ -1328,17 +1361,18 @@
      * Configure reader and preview outputs and wait until done.
      */
     private void configureReaderAndPreviewOutputs() throws Exception {
-        if (mPreviewSurface == null || mReaderSurface == null) {
+        if (mPreviewSurface == null || mTestRule.getReaderSurface() == null) {
             throw new IllegalStateException("preview and reader surface must be initilized first");
         }
-        mCameraSessionListener = new BlockingSessionCallback();
+        mTestRule.setCameraSessionListener(new BlockingSessionCallback());
         List<Surface> outputSurfaces = new ArrayList<>();
-        if (mStaticInfo.isColorOutputSupported()) {
+        if (mTestRule.getStaticInfo().isColorOutputSupported()) {
             outputSurfaces.add(mPreviewSurface);
         }
-        outputSurfaces.add(mReaderSurface);
-        mCameraSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces,
-                mCameraSessionListener, mHandler);
+        outputSurfaces.add(mTestRule.getReaderSurface());
+        mTestRule.setCameraSession(CameraTestUtils.configureCameraSession(
+                mTestRule.getCamera(), outputSurfaces,
+                mTestRule.getCameraSessionListener(), mTestRule.getHandler()));
     }
 
     /**
@@ -1347,21 +1381,24 @@
      * @param format The format used to create ImageReader instance.
      */
     private void initializeImageReader(String cameraId, int format) throws Exception {
-        mOrderedPreviewSizes = CameraTestUtils.getSortedSizesForFormat(
-                cameraId, mCameraManager, format,
-                CameraTestUtils.getPreviewSizeBound(mWindowManager,
-                    CameraTestUtils.PREVIEW_SIZE_BOUND));
-        Size maxPreviewSize = mOrderedPreviewSizes.get(0);
-        createDefaultImageReader(maxPreviewSize, format, NUM_MAX_IMAGES, /*listener*/null);
+        mTestRule.setOrderedPreviewSizes(CameraTestUtils.getSortedSizesForFormat(
+                cameraId, mTestRule.getCameraManager(), format,
+                CameraTestUtils.getPreviewSizeBound(mTestRule.getWindowManager(),
+                        CameraTestUtils.PREVIEW_SIZE_BOUND)));
+        Size maxPreviewSize = mTestRule.getOrderedPreviewSizes().get(0);
+        mTestRule.createDefaultImageReader(
+                maxPreviewSize, format, NUM_MAX_IMAGES, /*listener*/null);
         updatePreviewSurface(maxPreviewSize);
     }
 
     private void simpleOpenCamera(String cameraId) throws Exception {
-        mCamera = CameraTestUtils.openCamera(
-                mCameraManager, cameraId, mCameraListener, mHandler);
-        mCollector.setCameraId(cameraId);
-        mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId),
-                CheckLevel.ASSERT, /*collector*/null);
+        mTestRule.setCamera(CameraTestUtils.openCamera(
+                mTestRule.getCameraManager(), cameraId,
+                mTestRule.getCameraListener(), mTestRule.getHandler()));
+        mTestRule.getCollector().setCameraId(cameraId);
+        mTestRule.setStaticInfo(new StaticMetadata(
+                mTestRule.getCameraManager().getCameraCharacteristics(cameraId),
+                CheckLevel.ASSERT, /*collector*/null));
     }
 
     /**
@@ -1514,4 +1551,4 @@
         }
 
     }
-}
+}
\ No newline at end of file
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index e2bbb9c..918daeb 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2.cts;
 
 import static android.hardware.camera2.cts.CameraTestUtils.*;
+import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.*;
 
 import android.content.Context;
 import android.graphics.ImageFormat;
@@ -38,12 +39,16 @@
 import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation;
 import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.CamcorderProfile;
 import android.media.Image;
 import android.media.ImageReader;
 import android.media.ImageWriter;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Size;
+import android.view.Display;
 import android.view.Surface;
+import android.view.WindowManager;
 
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 
@@ -1807,4 +1812,810 @@
         return precaptureComplete;
     }
 
+    /**
+     * Test for making sure that all expected mandatory stream combinations are present and
+     * advertised accordingly.
+     */
+    @Test
+    public void testVerifyMandatoryOutputCombinationTables() throws Exception {
+       final int[][] LEGACY_COMBINATIONS = {
+            // Simple preview, GPU video processing, or no-preview video recording
+            {PRIV, MAXIMUM},
+            // No-viewfinder still image capture
+            {JPEG, MAXIMUM},
+            // In-application video/image processing
+            {YUV,  MAXIMUM},
+            // Standard still imaging.
+            {PRIV, PREVIEW,  JPEG, MAXIMUM},
+            // In-app processing plus still capture.
+            {YUV,  PREVIEW,  JPEG, MAXIMUM},
+            // Standard recording.
+            {PRIV, PREVIEW,  PRIV, PREVIEW},
+            // Preview plus in-app processing.
+            {PRIV, PREVIEW,  YUV,  PREVIEW},
+            // Still capture plus in-app processing.
+            {PRIV, PREVIEW,  YUV,  PREVIEW,  JPEG, MAXIMUM}
+        };
+
+        final int[][] LIMITED_COMBINATIONS = {
+            // High-resolution video recording with preview.
+            {PRIV, PREVIEW,  PRIV, RECORD },
+            // High-resolution in-app video processing with preview.
+            {PRIV, PREVIEW,  YUV , RECORD },
+            // Two-input in-app video processing.
+            {YUV , PREVIEW,  YUV , RECORD },
+            // High-resolution recording with video snapshot.
+            {PRIV, PREVIEW,  PRIV, RECORD,   JPEG, RECORD  },
+            // High-resolution in-app processing with video snapshot.
+            {PRIV, PREVIEW,  YUV,  RECORD,   JPEG, RECORD  },
+            // Two-input in-app processing with still capture.
+            {YUV , PREVIEW,  YUV,  PREVIEW,  JPEG, MAXIMUM }
+        };
+
+        final int[][] BURST_COMBINATIONS = {
+            // Maximum-resolution GPU processing with preview.
+            {PRIV, PREVIEW,  PRIV, MAXIMUM },
+            // Maximum-resolution in-app processing with preview.
+            {PRIV, PREVIEW,  YUV,  MAXIMUM },
+            // Maximum-resolution two-input in-app processing.
+            {YUV,  PREVIEW,  YUV,  MAXIMUM },
+        };
+
+        final int[][] FULL_COMBINATIONS = {
+            // Video recording with maximum-size video snapshot.
+            {PRIV, PREVIEW,  PRIV, PREVIEW,  JPEG, MAXIMUM },
+            // Standard video recording plus maximum-resolution in-app processing.
+            {YUV,  VGA,      PRIV, PREVIEW,  YUV,  MAXIMUM },
+            // Preview plus two-input maximum-resolution in-app processing.
+            {YUV,  VGA,      YUV,  PREVIEW,  YUV,  MAXIMUM }
+        };
+
+        final int[][] RAW_COMBINATIONS = {
+            // No-preview DNG capture.
+            {RAW,  MAXIMUM },
+            // Standard DNG capture.
+            {PRIV, PREVIEW,  RAW,  MAXIMUM },
+            // In-app processing plus DNG capture.
+            {YUV,  PREVIEW,  RAW,  MAXIMUM },
+            // Video recording with DNG capture.
+            {PRIV, PREVIEW,  PRIV, PREVIEW,  RAW, MAXIMUM},
+            // Preview with in-app processing and DNG capture.
+            {PRIV, PREVIEW,  YUV,  PREVIEW,  RAW, MAXIMUM},
+            // Two-input in-app processing plus DNG capture.
+            {YUV,  PREVIEW,  YUV,  PREVIEW,  RAW, MAXIMUM},
+            // Still capture with simultaneous JPEG and DNG.
+            {PRIV, PREVIEW,  JPEG, MAXIMUM,  RAW, MAXIMUM},
+            // In-app processing with simultaneous JPEG and DNG.
+            {YUV,  PREVIEW,  JPEG, MAXIMUM,  RAW, MAXIMUM}
+        };
+
+        final int[][] LEVEL_3_COMBINATIONS = {
+            // In-app viewfinder analysis with dynamic selection of output format
+            {PRIV, PREVIEW, PRIV, VGA, YUV, MAXIMUM, RAW, MAXIMUM},
+            // In-app viewfinder analysis with dynamic selection of output format
+            {PRIV, PREVIEW, PRIV, VGA, JPEG, MAXIMUM, RAW, MAXIMUM}
+        };
+
+        final int[][][] TABLES =
+                { LEGACY_COMBINATIONS, LIMITED_COMBINATIONS, BURST_COMBINATIONS, FULL_COMBINATIONS,
+                  RAW_COMBINATIONS, LEVEL_3_COMBINATIONS };
+
+        sanityCheckConfigurationTables(TABLES);
+
+        for (String id : mCameraIdsUnderTest) {
+            openDevice(id);
+            MandatoryStreamCombination[] combinations =
+                    mStaticInfo.getCharacteristics().get(
+                            CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS);
+            if ((combinations == null) || (combinations.length == 0)) {
+                Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test");
+                closeDevice(id);
+                continue;
+            }
+
+            MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, mContext);
+            try {
+                if (mStaticInfo.isColorOutputSupported()) {
+                    for (int[] c : LEGACY_COMBINATIONS) {
+                        assertTrue(String.format("Expected static stream combination: %s not " +
+                                    "found among the available mandatory combinations",
+                                    maxSizes.combinationToString(c)),
+                                isMandatoryCombinationAvailable(c, maxSizes, combinations));
+                    }
+                }
+
+                if (!mStaticInfo.isHardwareLevelLegacy()) {
+                    if (mStaticInfo.isColorOutputSupported()) {
+                        for (int[] c : LIMITED_COMBINATIONS) {
+                            assertTrue(String.format("Expected static stream combination: %s not " +
+                                        "found among the available mandatory combinations",
+                                        maxSizes.combinationToString(c)),
+                                    isMandatoryCombinationAvailable(c, maxSizes, combinations));
+                        }
+                    }
+
+                    if (mStaticInfo.isCapabilitySupported(
+                            CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
+                        for (int[] c : BURST_COMBINATIONS) {
+                            assertTrue(String.format("Expected static stream combination: %s not " +
+                                        "found among the available mandatory combinations",
+                                        maxSizes.combinationToString(c)),
+                                    isMandatoryCombinationAvailable(c, maxSizes, combinations));
+                        }
+                    }
+
+                    if (mStaticInfo.isHardwareLevelAtLeastFull()) {
+                        for (int[] c : FULL_COMBINATIONS) {
+                            assertTrue(String.format("Expected static stream combination: %s not " +
+                                        "found among the available mandatory combinations",
+                                        maxSizes.combinationToString(c)),
+                                    isMandatoryCombinationAvailable(c, maxSizes, combinations));
+                        }
+                    }
+
+                    if (mStaticInfo.isCapabilitySupported(
+                            CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
+                        for (int[] c : RAW_COMBINATIONS) {
+                            assertTrue(String.format("Expected static stream combination: %s not " +
+                                        "found among the available mandatory combinations",
+                                        maxSizes.combinationToString(c)),
+                                    isMandatoryCombinationAvailable(c, maxSizes, combinations));
+                        }
+                    }
+
+                    if (mStaticInfo.isHardwareLevelAtLeast(
+                            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) {
+                        for (int[] c: LEVEL_3_COMBINATIONS) {
+                            assertTrue(String.format("Expected static stream combination: %s not " +
+                                        "found among the available mandatory combinations",
+                                        maxSizes.combinationToString(c)),
+                                    isMandatoryCombinationAvailable(c, maxSizes, combinations));
+                        }
+                    }
+                }
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    /**
+     * Test for making sure that all expected reprocessable mandatory stream combinations are
+     * present and advertised accordingly.
+     */
+    @Test
+    public void testVerifyReprocessMandatoryOutputCombinationTables() throws Exception {
+        final int[][] LIMITED_COMBINATIONS = {
+            // Input           Outputs
+            {PRIV, MAXIMUM,    JPEG, MAXIMUM},
+            {YUV , MAXIMUM,    JPEG, MAXIMUM},
+            {PRIV, MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM},
+            {YUV , MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM},
+            {PRIV, MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM},
+            {YUV , MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM},
+            {PRIV, MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+            {YUV,  MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+        };
+
+        final int[][] FULL_COMBINATIONS = {
+            // Input           Outputs
+            {YUV , MAXIMUM,    PRIV, PREVIEW},
+            {YUV , MAXIMUM,    YUV , PREVIEW},
+            {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , RECORD},
+            {YUV , MAXIMUM,    PRIV, PREVIEW, YUV , RECORD},
+            {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , MAXIMUM},
+            {PRIV, MAXIMUM,    YUV , PREVIEW, YUV , MAXIMUM},
+            {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+            {YUV , MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+        };
+
+        final int[][] RAW_COMBINATIONS = {
+            // Input           Outputs
+            {PRIV, MAXIMUM,    YUV , PREVIEW, RAW , MAXIMUM},
+            {YUV , MAXIMUM,    YUV , PREVIEW, RAW , MAXIMUM},
+            {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {YUV , MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {PRIV, MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {YUV , MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {PRIV, MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+            {YUV , MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+            {PRIV, MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+            {YUV , MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+        };
+
+        final int[][] LEVEL_3_COMBINATIONS = {
+            // Input          Outputs
+            // In-app viewfinder analysis with YUV->YUV ZSL and RAW
+            {YUV , MAXIMUM,   PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM},
+            // In-app viewfinder analysis with PRIV->JPEG ZSL and RAW
+            {PRIV, MAXIMUM,   PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM},
+            // In-app viewfinder analysis with YUV->JPEG ZSL and RAW
+            {YUV , MAXIMUM,   PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM},
+        };
+
+        final int[][][] TABLES =
+                { LIMITED_COMBINATIONS, FULL_COMBINATIONS, RAW_COMBINATIONS, LEVEL_3_COMBINATIONS };
+
+        sanityCheckConfigurationTables(TABLES);
+
+        for (String id : mCameraIdsUnderTest) {
+            openDevice(id);
+            MandatoryStreamCombination[] cs = mStaticInfo.getCharacteristics().get(
+                    CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS);
+            if ((cs == null) || (cs.length == 0)) {
+                Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test");
+                closeDevice(id);
+                continue;
+            }
+
+            boolean supportYuvReprocess = mStaticInfo.isCapabilitySupported(
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
+            boolean supportOpaqueReprocess = mStaticInfo.isCapabilitySupported(
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
+            if (!supportYuvReprocess && !supportOpaqueReprocess) {
+                Log.i(TAG, "No reprocess support for camera: " + id + " skip test");
+                closeDevice(id);
+                continue;
+            }
+
+            MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, mContext);
+            try {
+                for (int[] c : LIMITED_COMBINATIONS) {
+                    assertTrue(String.format("Expected static reprocessable stream combination:" +
+                                "%s not found among the available mandatory combinations",
+                                maxSizes.reprocessCombinationToString(c)),
+                            isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs));
+                }
+
+                if (mStaticInfo.isHardwareLevelAtLeastFull()) {
+                    for (int[] c : FULL_COMBINATIONS) {
+                        assertTrue(String.format(
+                                    "Expected static reprocessable stream combination:" +
+                                    "%s not found among the available mandatory combinations",
+                                    maxSizes.reprocessCombinationToString(c)),
+                                isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs));
+                    }
+                }
+
+                if (mStaticInfo.isCapabilitySupported(
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
+                    for (int[] c : RAW_COMBINATIONS) {
+                        assertTrue(String.format(
+                                    "Expected static reprocessable stream combination:" +
+                                    "%s not found among the available mandatory combinations",
+                                    maxSizes.reprocessCombinationToString(c)),
+                                isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs));
+                    }
+                }
+
+                if (mStaticInfo.isHardwareLevelAtLeast(
+                            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) {
+                    for (int[] c : LEVEL_3_COMBINATIONS) {
+                        assertTrue(String.format(
+                                    "Expected static reprocessable stream combination:" +
+                                    "%s not found among the available mandatory combinations",
+                                    maxSizes.reprocessCombinationToString(c)),
+                                isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs));
+                    }
+                }
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    private boolean isMandatoryCombinationAvailable(final int[] combination,
+            final MaxStreamSizes maxSizes,
+            final MandatoryStreamCombination[] availableCombinations) {
+        return isMandatoryCombinationAvailable(combination, maxSizes, /*isInput*/ false,
+                availableCombinations);
+    }
+
+    private boolean isMandatoryCombinationAvailable(final int[] combination,
+            final MaxStreamSizes maxSizes, boolean isInput,
+            final MandatoryStreamCombination[] availableCombinations) {
+        // Static combinations to be verified can be composed of multiple entries
+        // that have the following layout (format, size). In case "isInput" is set,
+        // the first stream configuration entry will contain the input format and size
+        // as well as the first matching output.
+        int streamCount = combination.length / 2;
+        ArrayList<Pair<Pair<Integer, Boolean>, Size>> currentCombination =
+                new ArrayList<Pair<Pair<Integer, Boolean>, Size>>(streamCount);
+        for (int i = 0; i < combination.length; i += 2) {
+            if (isInput && (i == 0)) {
+                Size sz = maxSizes.getMaxInputSizeForFormat(combination[i]);
+                currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]),
+                            new Boolean(true)), sz));
+                currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]),
+                            new Boolean(false)), sz));
+            } else {
+                Size sz = maxSizes.getOutputSizeForFormat(combination[i], combination[i+1]);
+                currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]),
+                            new Boolean(false)), sz));
+            }
+        }
+
+        for (MandatoryStreamCombination c : availableCombinations) {
+            List<MandatoryStreamInformation> streamInfoList = c.getStreamsInformation();
+            if ((streamInfoList.size() == currentCombination.size()) &&
+                    (isInput == c.isReprocessable())) {
+                ArrayList<Pair<Pair<Integer, Boolean>, Size>> expected =
+                        new ArrayList<Pair<Pair<Integer, Boolean>, Size>>(currentCombination);
+
+                for (MandatoryStreamInformation streamInfo : streamInfoList) {
+                    Size maxSize = CameraTestUtils.getMaxSize(
+                            streamInfo.getAvailableSizes().toArray(new Size[0]));
+                    Pair p = Pair.create(Pair.create(new Integer(streamInfo.getFormat()),
+                            new Boolean(streamInfo.isInput())), maxSize);
+                    if (expected.contains(p)) {
+                        expected.remove(p);
+                    }
+                }
+
+                if (expected.isEmpty()) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Sanity check the configuration tables.
+     */
+    private void sanityCheckConfigurationTables(final int[][][] tables) throws Exception {
+        int tableIdx = 0;
+        for (int[][] table : tables) {
+            int rowIdx = 0;
+            for (int[] row : table) {
+                assertTrue(String.format("Odd number of entries for table %d row %d: %s ",
+                                tableIdx, rowIdx, Arrays.toString(row)),
+                        (row.length % 2) == 0);
+                for (int i = 0; i < row.length; i += 2) {
+                    int format = row[i];
+                    int maxSize = row[i + 1];
+                    assertTrue(String.format("table %d row %d index %d format not valid: %d",
+                                    tableIdx, rowIdx, i, format),
+                            format == PRIV || format == JPEG || format == YUV || format == RAW);
+                    assertTrue(String.format("table %d row %d index %d max size not valid: %d",
+                                    tableIdx, rowIdx, i + 1, maxSize),
+                            maxSize == PREVIEW || maxSize == RECORD ||
+                            maxSize == MAXIMUM || maxSize == VGA);
+                }
+                rowIdx++;
+            }
+            tableIdx++;
+        }
+    }
+
+    /**
+     * Simple holder for resolutions to use for different camera outputs and size limits.
+     */
+    static class MaxStreamSizes {
+        // Format shorthands
+        static final int PRIV = ImageFormat.PRIVATE;
+        static final int JPEG = ImageFormat.JPEG;
+        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;
+        static final int RECORD  = 1;
+        static final int MAXIMUM = 2;
+        static final int VGA = 3;
+        static final int VGA_FULL_FOV = 4;
+        static final int MAX_30FPS = 5;
+        static final int RESOLUTION_COUNT = 6;
+
+        static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30;
+
+        public MaxStreamSizes(StaticMetadata sm, String cameraId, Context context) {
+            Size[] privSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.PRIVATE,
+                    StaticMetadata.StreamDirection.Output);
+            Size[] yuvSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888,
+                    StaticMetadata.StreamDirection.Output);
+            Size[] y8Sizes = sm.getAvailableSizesForFormatChecked(ImageFormat.Y8,
+                    StaticMetadata.StreamDirection.Output);
+            Size[] jpegSizes = sm.getJpegOutputSizesChecked();
+            Size[] rawSizes = sm.getRawOutputSizesChecked();
+            Size[] heicSizes = sm.getHeicOutputSizesChecked();
+
+            Size maxPreviewSize = getMaxPreviewSize(context, cameraId);
+
+            maxRawSize = (rawSizes.length != 0) ? CameraTestUtils.getMaxSize(rawSizes) : null;
+
+            StreamConfigurationMap configs = sm.getCharacteristics().get(
+                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+            if (sm.isColorOutputSupported()) {
+                maxPrivSizes[PREVIEW] = getMaxSize(privSizes, maxPreviewSize);
+                maxYuvSizes[PREVIEW]  = getMaxSize(yuvSizes, maxPreviewSize);
+                maxJpegSizes[PREVIEW] = getMaxSize(jpegSizes, maxPreviewSize);
+
+                if (sm.isExternalCamera()) {
+                    maxPrivSizes[RECORD] = getMaxExternalRecordingSize(cameraId, configs);
+                    maxYuvSizes[RECORD]  = getMaxExternalRecordingSize(cameraId, configs);
+                    maxJpegSizes[RECORD] = getMaxExternalRecordingSize(cameraId, configs);
+                } else {
+                    maxPrivSizes[RECORD] = getMaxRecordingSize(cameraId);
+                    maxYuvSizes[RECORD]  = getMaxRecordingSize(cameraId);
+                    maxJpegSizes[RECORD] = getMaxRecordingSize(cameraId);
+                }
+
+                maxPrivSizes[MAXIMUM] = CameraTestUtils.getMaxSize(privSizes);
+                maxYuvSizes[MAXIMUM] = CameraTestUtils.getMaxSize(yuvSizes);
+                maxJpegSizes[MAXIMUM] = CameraTestUtils.getMaxSize(jpegSizes);
+
+                // Must always be supported, add unconditionally
+                final Size vgaSize = new Size(640, 480);
+                maxPrivSizes[VGA] = vgaSize;
+                maxYuvSizes[VGA] = vgaSize;
+                maxJpegSizes[VGA] = vgaSize;
+
+                if (sm.isMonochromeWithY8()) {
+                    maxY8Sizes[PREVIEW]  = getMaxSize(y8Sizes, maxPreviewSize);
+                    if (sm.isExternalCamera()) {
+                        maxY8Sizes[RECORD]  = getMaxExternalRecordingSize(cameraId, configs);
+                    } else {
+                        maxY8Sizes[RECORD]  = getMaxRecordingSize(cameraId);
+                    }
+                    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;
+                }
+            }
+            if (sm.isColorOutputSupported() && !sm.isHardwareLevelLegacy()) {
+                // VGA resolution, but with aspect ratio matching full res FOV
+                float fullFovAspect = maxYuvSizes[MAXIMUM].getWidth() /
+                    (float) maxYuvSizes[MAXIMUM].getHeight();
+                Size vgaFullFovSize = new Size(640, (int) (640 / fullFovAspect));
+
+                maxPrivSizes[VGA_FULL_FOV] = vgaFullFovSize;
+                maxYuvSizes[VGA_FULL_FOV] = vgaFullFovSize;
+                maxJpegSizes[VGA_FULL_FOV] = vgaFullFovSize;
+                if (sm.isMonochromeWithY8()) {
+                    maxY8Sizes[VGA_FULL_FOV] = vgaFullFovSize;
+                }
+
+                // Max resolution that runs at 30fps
+
+                Size maxPriv30fpsSize = null;
+                Size maxYuv30fpsSize = null;
+                Size maxY830fpsSize = null;
+                Size maxJpeg30fpsSize = null;
+                Comparator<Size> comparator = new SizeComparator();
+                for (Map.Entry<Size, Long> e :
+                             sm.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.PRIVATE).
+                             entrySet()) {
+                    Size s = e.getKey();
+                    Long minDuration = e.getValue();
+                    Log.d(TAG, String.format("Priv Size: %s, duration %d limit %d", s, minDuration,
+                                FRAME_DURATION_30FPS_NSEC));
+                    if (minDuration <= FRAME_DURATION_30FPS_NSEC) {
+                        if (maxPriv30fpsSize == null ||
+                                comparator.compare(maxPriv30fpsSize, s) < 0) {
+                            maxPriv30fpsSize = s;
+                        }
+                    }
+                }
+                assertTrue("No PRIVATE resolution available at 30fps!", maxPriv30fpsSize != null);
+
+                for (Map.Entry<Size, Long> e :
+                             sm.getAvailableMinFrameDurationsForFormatChecked(
+                                     ImageFormat.YUV_420_888).
+                             entrySet()) {
+                    Size s = e.getKey();
+                    Long minDuration = e.getValue();
+                    Log.d(TAG, String.format("YUV Size: %s, duration %d limit %d", s, minDuration,
+                                FRAME_DURATION_30FPS_NSEC));
+                    if (minDuration <= FRAME_DURATION_30FPS_NSEC) {
+                        if (maxYuv30fpsSize == null ||
+                                comparator.compare(maxYuv30fpsSize, s) < 0) {
+                            maxYuv30fpsSize = s;
+                        }
+                    }
+                }
+                assertTrue("No YUV_420_888 resolution available at 30fps!",
+                        maxYuv30fpsSize != null);
+
+                if (sm.isMonochromeWithY8()) {
+                    for (Map.Entry<Size, Long> e :
+                                 sm.getAvailableMinFrameDurationsForFormatChecked(
+                                         ImageFormat.Y8).
+                                 entrySet()) {
+                        Size s = e.getKey();
+                        Long minDuration = e.getValue();
+                        Log.d(TAG, String.format("Y8 Size: %s, duration %d limit %d",
+                                s, minDuration, FRAME_DURATION_30FPS_NSEC));
+                        if (minDuration <= FRAME_DURATION_30FPS_NSEC) {
+                            if (maxY830fpsSize == null ||
+                                    comparator.compare(maxY830fpsSize, s) < 0) {
+                                maxY830fpsSize = s;
+                            }
+                        }
+                    }
+                    assertTrue("No Y8 resolution available at 30fps!", maxY830fpsSize != null);
+                }
+
+                for (Map.Entry<Size, Long> e :
+                             sm.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.JPEG).
+                             entrySet()) {
+                    Size s = e.getKey();
+                    Long minDuration = e.getValue();
+                    Log.d(TAG, String.format("JPEG Size: %s, duration %d limit %d", s, minDuration,
+                                FRAME_DURATION_30FPS_NSEC));
+                    if (minDuration <= FRAME_DURATION_30FPS_NSEC) {
+                        if (maxJpeg30fpsSize == null ||
+                                comparator.compare(maxJpeg30fpsSize, s) < 0) {
+                            maxJpeg30fpsSize = s;
+                        }
+                    }
+                }
+                assertTrue("No JPEG resolution available at 30fps!", maxJpeg30fpsSize != null);
+
+                maxPrivSizes[MAX_30FPS] = maxPriv30fpsSize;
+                maxYuvSizes[MAX_30FPS] = maxYuv30fpsSize;
+                maxY8Sizes[MAX_30FPS] = maxY830fpsSize;
+                maxJpegSizes[MAX_30FPS] = maxJpeg30fpsSize;
+            }
+
+            Size[] privInputSizes = configs.getInputSizes(ImageFormat.PRIVATE);
+            maxInputPrivSize = privInputSizes != null ?
+                    CameraTestUtils.getMaxSize(privInputSizes) : null;
+            Size[] yuvInputSizes = configs.getInputSizes(ImageFormat.YUV_420_888);
+            maxInputYuvSize = yuvInputSizes != null ?
+                    CameraTestUtils.getMaxSize(yuvInputSizes) : null;
+            Size[] y8InputSizes = configs.getInputSizes(ImageFormat.Y8);
+            maxInputY8Size = y8InputSizes != null ?
+                    CameraTestUtils.getMaxSize(y8InputSizes) : null;
+        }
+
+        private final Size[] maxPrivSizes = new Size[RESOLUTION_COUNT];
+        private final Size[] maxJpegSizes = new Size[RESOLUTION_COUNT];
+        private final Size[] maxYuvSizes = new Size[RESOLUTION_COUNT];
+        private final Size[] maxY8Sizes = new Size[RESOLUTION_COUNT];
+        private final Size[] maxHeicSizes = new Size[RESOLUTION_COUNT];
+        private final Size maxRawSize;
+        // TODO: support non maximum reprocess input.
+        private final Size maxInputPrivSize;
+        private final Size maxInputYuvSize;
+        private final Size maxInputY8Size;
+
+        public final Size getOutputSizeForFormat(int format, int resolutionIndex) {
+            if (resolutionIndex >= RESOLUTION_COUNT) {
+                return new Size(0, 0);
+            }
+
+            switch (format) {
+                case PRIV:
+                    return maxPrivSizes[resolutionIndex];
+                case YUV:
+                    return maxYuvSizes[resolutionIndex];
+                case JPEG:
+                    return maxJpegSizes[resolutionIndex];
+                case Y8:
+                    return maxY8Sizes[resolutionIndex];
+                case HEIC:
+                    return maxHeicSizes[resolutionIndex];
+                case RAW:
+                    return maxRawSize;
+                default:
+                    return new Size(0, 0);
+            }
+        }
+
+        public final Size getMaxInputSizeForFormat(int format) {
+            switch (format) {
+                case PRIV:
+                    return maxInputPrivSize;
+                case YUV:
+                    return maxInputYuvSize;
+                case Y8:
+                    return maxInputY8Size;
+                default:
+                    return new Size(0, 0);
+            }
+        }
+
+        static public String combinationToString(int[] combination) {
+            StringBuilder b = new StringBuilder("{ ");
+            for (int i = 0; i < combination.length; i += 2) {
+                int format = combination[i];
+                int sizeLimit = combination[i + 1];
+
+                appendFormatSize(b, format, sizeLimit);
+                b.append(" ");
+            }
+            b.append("}");
+            return b.toString();
+        }
+
+        static public String reprocessCombinationToString(int[] reprocessCombination) {
+            // reprocessConfig[0..1] is the input configuration
+            StringBuilder b = new StringBuilder("Input: ");
+            appendFormatSize(b, reprocessCombination[0], reprocessCombination[1]);
+
+            // reprocessCombnation[0..1] is also output combination to be captured as reprocess
+            // input.
+            b.append(", Outputs: { ");
+            for (int i = 0; i < reprocessCombination.length; i += 2) {
+                int format = reprocessCombination[i];
+                int sizeLimit = reprocessCombination[i + 1];
+
+                appendFormatSize(b, format, sizeLimit);
+                b.append(" ");
+            }
+            b.append("}");
+            return b.toString();
+        }
+
+        static private void appendFormatSize(StringBuilder b, int format, int Size) {
+            switch (format) {
+                case PRIV:
+                    b.append("[PRIV, ");
+                    break;
+                case JPEG:
+                    b.append("[JPEG, ");
+                    break;
+                case YUV:
+                    b.append("[YUV, ");
+                    break;
+                case Y8:
+                    b.append("[Y8, ");
+                    break;
+                case RAW:
+                    b.append("[RAW, ");
+                    break;
+                default:
+                    b.append("[UNK, ");
+                    break;
+            }
+
+            switch (Size) {
+                case PREVIEW:
+                    b.append("PREVIEW]");
+                    break;
+                case RECORD:
+                    b.append("RECORD]");
+                    break;
+                case MAXIMUM:
+                    b.append("MAXIMUM]");
+                    break;
+                case VGA:
+                    b.append("VGA]");
+                    break;
+                case VGA_FULL_FOV:
+                    b.append("VGA_FULL_FOV]");
+                    break;
+                case MAX_30FPS:
+                    b.append("MAX_30FPS]");
+                    break;
+                default:
+                    b.append("UNK]");
+                    break;
+            }
+        }
+    }
+
+    private static Size getMaxRecordingSize(String cameraId) {
+        int id = Integer.valueOf(cameraId);
+
+        int quality =
+                CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2160P) ?
+                    CamcorderProfile.QUALITY_2160P :
+                CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_1080P) ?
+                    CamcorderProfile.QUALITY_1080P :
+                CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_720P) ?
+                    CamcorderProfile.QUALITY_720P :
+                CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_480P) ?
+                    CamcorderProfile.QUALITY_480P :
+                CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QVGA) ?
+                    CamcorderProfile.QUALITY_QVGA :
+                CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_CIF) ?
+                    CamcorderProfile.QUALITY_CIF :
+                CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QCIF) ?
+                    CamcorderProfile.QUALITY_QCIF :
+                    -1;
+
+        assertTrue("No recording supported for camera id " + cameraId, quality != -1);
+
+        CamcorderProfile maxProfile = CamcorderProfile.get(id, quality);
+        return new Size(maxProfile.videoFrameWidth, maxProfile.videoFrameHeight);
+    }
+
+    private static Size getMaxExternalRecordingSize(
+            String cameraId, StreamConfigurationMap config) {
+        final Size FULLHD = new Size(1920, 1080);
+
+        Size[] videoSizeArr = config.getOutputSizes(android.media.MediaRecorder.class);
+        List<Size> sizes = new ArrayList<Size>();
+        for (Size sz: videoSizeArr) {
+            if (sz.getWidth() <= FULLHD.getWidth() && sz.getHeight() <= FULLHD.getHeight()) {
+                sizes.add(sz);
+            }
+        }
+        List<Size> videoSizes = getAscendingOrderSizes(sizes, /*ascending*/false);
+        for (Size sz : videoSizes) {
+            long minFrameDuration = config.getOutputMinFrameDuration(
+                    android.media.MediaRecorder.class, sz);
+            // Give some margin for rounding error
+            if (minFrameDuration > (1e9 / 30.1)) {
+                Log.i(TAG, "External camera " + cameraId + " has max video size:" + sz);
+                return sz;
+            }
+        }
+        fail("Camera " + cameraId + " does not support any 30fps video output");
+        return FULLHD; // doesn't matter what size is returned here
+    }
+
+    /**
+     * Get maximum size in list that's equal or smaller to than the bound.
+     * Returns null if no size is smaller than or equal to the bound.
+     */
+    private static Size getMaxSize(Size[] sizes, Size bound) {
+        if (sizes == null || sizes.length == 0) {
+            throw new IllegalArgumentException("sizes was empty");
+        }
+
+        Size sz = null;
+        for (Size size : sizes) {
+            if (size.getWidth() <= bound.getWidth() && size.getHeight() <= bound.getHeight()) {
+
+                if (sz == null) {
+                    sz = size;
+                } else {
+                    long curArea = sz.getWidth() * (long) sz.getHeight();
+                    long newArea = size.getWidth() * (long) size.getHeight();
+                    if ( newArea > curArea ) {
+                        sz = size;
+                    }
+                }
+            }
+        }
+
+        assertTrue("No size under bound found: " + Arrays.toString(sizes) + " bound " + bound,
+                sz != null);
+
+        return sz;
+    }
+
+    private static Size getMaxPreviewSize(Context context, String cameraId) {
+        try {
+            WindowManager windowManager =
+                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+            Display display = windowManager.getDefaultDisplay();
+
+            int width = display.getWidth();
+            int height = display.getHeight();
+
+            if (height > width) {
+                height = width;
+                width = display.getHeight();
+            }
+
+            CameraManager camMgr =
+                (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+            List<Size> orderedPreviewSizes = CameraTestUtils.getSupportedPreviewSizes(
+                cameraId, camMgr, PREVIEW_SIZE_BOUND);
+
+            if (orderedPreviewSizes != null) {
+                for (Size size : orderedPreviewSizes) {
+                    if (width >= size.getWidth() &&
+                        height >= size.getHeight())
+                        return size;
+                }
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "getMaxPreviewSize Failed. "+e.toString());
+        }
+        return PREVIEW_SIZE_BOUND;
+    }
 }
diff --git a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
index 1ffa501..a6c477c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -310,6 +310,7 @@
                 requestKeys.add(CaptureRequest.CONTROL_MODE);
                 requestKeys.add(CaptureRequest.CONTROL_SCENE_MODE);
                 requestKeys.add(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE);
+                requestKeys.add(CaptureRequest.CONTROL_ZOOM_RATIO);
                 requestKeys.add(CaptureRequest.FLASH_MODE);
                 requestKeys.add(CaptureRequest.JPEG_GPS_LOCATION);
                 requestKeys.add(CaptureRequest.JPEG_ORIENTATION);
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index 25fde0e..991649e 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -1033,6 +1033,9 @@
                 // stopPreview must be called here to make sure next time a preview stream
                 // is created with new size.
                 stopPreview();
+                // Drain the results after each combination. Depending on the device the results
+                // can be relatively big and could accumulate fairly quickly after many iterations.
+                resultListener.drain();
             }
     }
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidBasicTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
similarity index 78%
rename from tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidBasicTestCase.java
rename to tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
index c240065..91f6b80 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidBasicTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
@@ -20,7 +20,6 @@
 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
 
 import android.content.Context;
-import android.graphics.ImageFormat;
 import android.graphics.Rect;
 
 import android.hardware.camera2.cts.CameraTestUtils;
@@ -41,7 +40,6 @@
 import android.media.ImageReader;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.test.AndroidTestCase;
 import android.util.Log;
 import android.view.Surface;
 import android.view.WindowManager;
@@ -49,6 +47,8 @@
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 
+import org.junit.rules.ExternalResource;
+
 import java.io.File;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -56,7 +56,7 @@
 import java.util.HashMap;
 import java.util.List;
 
-public class Camera2AndroidBasicTestCase extends AndroidTestCase {
+public class Camera2AndroidTestRule extends ExternalResource {
     private static final String TAG = "Camera2AndroidBasicTestCase";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
@@ -64,34 +64,115 @@
     protected static final Size DEFAULT_CAPTURE_SIZE = new Size(640, 480);
     protected static final int CAPTURE_WAIT_TIMEOUT_MS = 5000;
 
-    protected CameraManager mCameraManager;
-    protected CameraDevice mCamera;
-    protected CameraCaptureSession mCameraSession;
-    protected BlockingSessionCallback mCameraSessionListener;
-    protected BlockingStateCallback mCameraListener;
-    protected String[] mCameraIdsUnderTest;
+    private CameraManager mCameraManager;
+    private CameraDevice mCamera;
+    private CameraCaptureSession mCameraSession;
+    private BlockingSessionCallback mCameraSessionListener;
+    private BlockingStateCallback mCameraListener;
+    private String[] mCameraIdsUnderTest;
     // include both standalone camera IDs and "hidden" physical camera IDs
-    protected String[] mAllCameraIds;
-    protected HashMap<String, StaticMetadata> mAllStaticInfo;
-    protected ImageReader mReader;
-    protected Surface mReaderSurface;
-    protected Handler mHandler;
-    protected HandlerThread mHandlerThread;
-    protected StaticMetadata mStaticInfo;
-    protected CameraErrorCollector mCollector;
-    protected List<Size> mOrderedPreviewSizes; // In descending order.
-    protected List<Size> mOrderedVideoSizes; // In descending order.
-    protected List<Size> mOrderedStillSizes; // In descending order.
-    protected String mDebugFileNameBase;
+    private String[] mAllCameraIds;
+    private HashMap<String, StaticMetadata> mAllStaticInfo;
+    private ImageReader mReader;
+    private Surface mReaderSurface;
+    private Handler mHandler;
+    private HandlerThread mHandlerThread;
+    private StaticMetadata mStaticInfo;
+    private CameraErrorCollector mCollector;
+    private List<Size> mOrderedPreviewSizes; // In descending order.
+    private List<Size> mOrderedVideoSizes; // In descending order.
+    private List<Size> mOrderedStillSizes; // In descending order.
+    private String mDebugFileNameBase;
 
-    protected WindowManager mWindowManager;
+    private WindowManager mWindowManager;
+    private Context mContext;
 
-    @Override
-    public void setContext(Context context) {
-        super.setContext(context);
-        mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
-        assertNotNull("Can't connect to camera manager!", mCameraManager);
-        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+    public Camera2AndroidTestRule(Context context) {
+        mContext = context;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public String[] getCameraIdsUnderTest() {
+        return mCameraIdsUnderTest;
+    }
+
+    public StaticMetadata getStaticInfo() {
+        return mStaticInfo;
+    }
+
+    public CameraManager getCameraManager() {
+        return mCameraManager;
+    }
+
+    public void setStaticInfo(StaticMetadata staticInfo) {
+        mStaticInfo = staticInfo;
+    }
+
+    public CameraCaptureSession getCameraSession() {
+        return mCameraSession;
+    }
+
+    public CameraDevice getCamera() {
+        return mCamera;
+    }
+
+    public void setCamera(CameraDevice camera) {
+        mCamera = camera;
+    }
+
+    public void setCameraSession(CameraCaptureSession session) {
+        mCameraSession = session;
+    }
+
+    public BlockingStateCallback getCameraListener() {
+        return mCameraListener;
+    }
+
+    public BlockingSessionCallback getCameraSessionListener() {
+        return mCameraSessionListener;
+    }
+
+    public Handler getHandler() {
+        return mHandler;
+    }
+
+    public void setCameraSessionListener(BlockingSessionCallback listener) {
+        mCameraSessionListener = listener;
+    }
+
+    public ImageReader getReader() {
+        return mReader;
+    }
+
+    public HashMap<String, StaticMetadata> getAllStaticInfo() {
+        return mAllStaticInfo;
+    }
+
+    public List<Size> getOrderedPreviewSizes() {
+        return mOrderedPreviewSizes;
+    }
+
+    public List<Size> getOrderedStillSizes() {
+        return mOrderedStillSizes;
+    }
+
+    public Surface getReaderSurface() {
+        return mReaderSurface;
+    }
+
+    public void setOrderedPreviewSizes(List<Size> sizes) {
+        mOrderedPreviewSizes = sizes;
+    }
+
+    public WindowManager getWindowManager() {
+        return mWindowManager;
+    }
+
+    public CameraErrorCollector getCollector() {
+        return mCollector;
     }
 
     /**
@@ -99,9 +180,11 @@
      * HandlerThread, Camera IDs, and CameraStateCallback etc.
      */
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    public void before() throws Exception {
+        Log.v(TAG, "Set up...");
+        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
+        assertNotNull("Can't connect to camera manager!", mCameraManager);
+        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         /**
          * Workaround for mockito and JB-MR2 incompatibility
          *
@@ -152,27 +235,26 @@
     }
 
     @Override
-    protected void tearDown() throws Exception {
-        String[] cameraIdsPostTest =
-                mCameraManager.getCameraIdListNoLazy();
-        assertNotNull("Camera ids shouldn't be null", cameraIdsPostTest);
-        Log.i(TAG, "Camera ids in setup:" + Arrays.toString(mCameraIdsUnderTest));
-        Log.i(TAG, "Camera ids in tearDown:" + Arrays.toString(cameraIdsPostTest));
-        assertTrue(
-                "Number of cameras changed from " + mCameraIdsUnderTest.length + " to " +
-                cameraIdsPostTest.length,
-                mCameraIdsUnderTest.length == cameraIdsPostTest.length);
-        mHandlerThread.quitSafely();
-        mHandler = null;
-        closeDefaultImageReader();
-
-        try {
-            mCollector.verify();
-        } catch (Throwable e) {
-            // When new Exception(e) is used, exception info will be printed twice.
-            throw new Exception(e.getMessage());
-        } finally {
-            super.tearDown();
+    public void after() {
+        Log.v(TAG, "Tear down...");
+        if (mCameraManager != null) {
+            try {
+                String[] cameraIdsPostTest = mCameraManager.getCameraIdListNoLazy();
+                assertNotNull("Camera ids shouldn't be null", cameraIdsPostTest);
+                Log.i(TAG, "Camera ids in setup:" + Arrays.toString(mCameraIdsUnderTest));
+                Log.i(TAG, "Camera ids in tearDown:" + Arrays.toString(cameraIdsPostTest));
+                assertTrue(
+                        "Number of cameras changed from " + mCameraIdsUnderTest.length + " to " +
+                                cameraIdsPostTest.length,
+                        mCameraIdsUnderTest.length == cameraIdsPostTest.length);
+                mHandlerThread.quitSafely();
+                mHandler = null;
+                closeDefaultImageReader();
+                mCollector.verify();
+            } catch (Throwable e) {
+                // When new Exception(e) is used, exception info will be printed twice.
+                throw new RuntimeException(e.getMessage());
+            }
         }
     }
 
@@ -184,7 +266,7 @@
      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
      * @param handler The handler camera device used to post callbacks.
      */
-    protected void startCapture(CaptureRequest request, boolean repeating,
+    public void startCapture(CaptureRequest request, boolean repeating,
             CaptureCallback listener, Handler handler) throws Exception {
         if (VERBOSE) Log.v(TAG, "Starting capture from device");
 
@@ -201,7 +283,7 @@
      * @param fast When it is true, {@link CameraDevice#flush} is called, the stop capture
      * could be faster.
      */
-    protected void stopCapture(boolean fast) throws Exception {
+    public void stopCapture(boolean fast) throws Exception {
         if (VERBOSE) Log.v(TAG, "Stopping capture");
 
         if (fast) {
@@ -225,7 +307,7 @@
      *
      * @param cameraId The id of the camera device to be opened.
      */
-    protected void openDevice(String cameraId) throws Exception {
+    public void openDevice(String cameraId) throws Exception {
         openDevice(cameraId, mCameraListener);
     }
 
@@ -235,7 +317,7 @@
      * @param cameraId The id of the camera device to be opened.
      * @param listener The {@link #BlockingStateCallback} used to wait for states.
      */
-    protected void openDevice(String cameraId, BlockingStateCallback listener) throws Exception {
+    public void openDevice(String cameraId, BlockingStateCallback listener) throws Exception {
         mCamera = CameraTestUtils.openCamera(
                 mCameraManager, cameraId, listener, mHandler);
         mCollector.setCameraId(cameraId);
@@ -258,7 +340,7 @@
      *
      * @param outputSurfaces The set of output surfaces to configure for this session
      */
-    protected void createSession(List<Surface> outputSurfaces) throws Exception {
+    public void createSession(List<Surface> outputSurfaces) throws Exception {
         mCameraSessionListener = new BlockingSessionCallback();
         mCameraSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces,
                 mCameraSessionListener, mHandler);
@@ -270,7 +352,7 @@
      *
      * @param outputSurfaces The set of output surfaces to configure for this session
      */
-    protected void createSessionByConfigs(List<OutputConfiguration> outputConfigs) throws Exception {
+    public void createSessionByConfigs(List<OutputConfiguration> outputConfigs) throws Exception {
         mCameraSessionListener = new BlockingSessionCallback();
         mCameraSession = CameraTestUtils.configureCameraSessionWithConfig(mCamera, outputConfigs,
                 mCameraSessionListener, mHandler);
@@ -286,7 +368,7 @@
      *
      * @param cameraId The id of the {@link #CameraDevice camera device} to be closed.
      */
-    protected void closeDevice(String cameraId) {
+    public void closeDevice(String cameraId) {
         closeDevice(cameraId, mCameraListener);
     }
 
@@ -301,7 +383,7 @@
      * @param cameraId The id of the camera device to be closed.
      * @param listener The BlockingStateCallback used to wait for states.
      */
-    protected void closeDevice(String cameraId, BlockingStateCallback listener) {
+    public void closeDevice(String cameraId, BlockingStateCallback listener) {
         if (mCamera != null) {
             if (!cameraId.equals(mCamera.getId())) {
                 throw new IllegalStateException("Try to close a device that is not opened yet");
@@ -337,7 +419,7 @@
      * @param listener The listener used by this ImageReader to notify
      *            callbacks.
      */
-    protected void createDefaultImageReader(Size size, int format, int maxNumImages,
+    public void createDefaultImageReader(Size size, int format, int maxNumImages,
             ImageReader.OnImageAvailableListener listener) throws Exception {
         closeDefaultImageReader();
 
@@ -362,7 +444,7 @@
      * @param listener The listener used by this ImageReader to notify
      *            callbacks.
      */
-    protected void createDefaultImageReader(Size size, int format, int maxNumImages, long usage,
+    public void createDefaultImageReader(Size size, int format, int maxNumImages, long usage,
             ImageReader.OnImageAvailableListener listener) throws Exception {
         closeDefaultImageReader();
 
@@ -382,7 +464,7 @@
      * @param listener The listener used by this ImageReader to notify callbacks.
      */
 
-    protected ImageReader createImageReader(Size size, int format, int maxNumImages,
+    public ImageReader createImageReader(Size size, int format, int maxNumImages,
             ImageReader.OnImageAvailableListener listener) throws Exception {
 
         ImageReader reader = null;
@@ -406,7 +488,7 @@
      * @param listener The listener used by this ImageReader to notify callbacks.
      */
 
-    protected ImageReader createImageReader(Size size, int format, int maxNumImages, long usage,
+    public ImageReader createImageReader(Size size, int format, int maxNumImages, long usage,
             ImageReader.OnImageAvailableListener listener) throws Exception {
         ImageReader reader = null;
         reader = ImageReader.newInstance(size.getWidth(), size.getHeight(),
@@ -420,7 +502,7 @@
     /**
      * Close the pending images then close current default {@link ImageReader} object.
      */
-    protected void closeDefaultImageReader() {
+    public void closeDefaultImageReader() {
         closeImageReader(mReader);
         mReader = null;
         mReaderSurface = null;
@@ -431,7 +513,7 @@
      *
      * @param reader
      */
-    protected void closeImageReader(ImageReader reader) {
+    public void closeImageReader(ImageReader reader) {
         if (reader != null) {
             try {
                 // Close all possible pending images first.
@@ -446,7 +528,7 @@
         }
     }
 
-    protected void checkImageReaderSessionConfiguration(String msg) throws Exception {
+    public void checkImageReaderSessionConfiguration(String msg) throws Exception {
         List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
         outputConfigs.add(new OutputConfiguration(mReaderSurface));
 
@@ -454,11 +536,11 @@
                 SessionConfiguration.SESSION_REGULAR, /*expectedResult*/ true, msg);
     }
 
-    protected CaptureRequest prepareCaptureRequest() throws Exception {
+    public CaptureRequest prepareCaptureRequest() throws Exception {
         return prepareCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
     }
 
-    protected CaptureRequest prepareCaptureRequest(int template) throws Exception {
+    public CaptureRequest prepareCaptureRequest(int template) throws Exception {
         List<Surface> outputSurfaces = new ArrayList<Surface>();
         Surface surface = mReader.getSurface();
         assertNotNull("Fail to get surface from ImageReader", surface);
@@ -467,7 +549,7 @@
                 .build();
     }
 
-    protected CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces,
+    public CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces,
             int template)
             throws Exception {
         createSession(surfaces);
@@ -482,7 +564,7 @@
         return captureBuilder;
     }
 
-    protected CaptureRequest.Builder prepareCaptureRequestForConfigs(
+    public CaptureRequest.Builder prepareCaptureRequestForConfigs(
             List<OutputConfiguration> outputConfigs, int template) throws Exception {
         createSessionByConfigs(outputConfigs);
 
@@ -506,7 +588,7 @@
      * @param closedBuffer The ByteBuffer from a closed Image. buffer invalid
      *            access will be skipped if it is null.
      */
-    protected void imageInvalidAccessTestAfterClose(Image closedImage,
+    public void imageInvalidAccessTestAfterClose(Image closedImage,
             Plane closedPlane, ByteBuffer closedBuffer) {
         if (closedImage == null) {
             throw new IllegalArgumentException(" closedImage must be non-null");
@@ -628,4 +710,4 @@
             // Expected.
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tests/camera/src/android/hardware/cts/CameraTestCase.java b/tests/camera/src/android/hardware/cts/CameraPerformanceTestHelper.java
similarity index 72%
rename from tests/camera/src/android/hardware/cts/CameraTestCase.java
rename to tests/camera/src/android/hardware/cts/CameraPerformanceTestHelper.java
index 1b4193b..379fad5 100644
--- a/tests/camera/src/android/hardware/cts/CameraTestCase.java
+++ b/tests/camera/src/android/hardware/cts/CameraPerformanceTestHelper.java
@@ -16,6 +16,10 @@
 
 package android.hardware.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.hardware.Camera;
 import android.hardware.Camera.AutoFocusCallback;
 import android.hardware.Camera.ErrorCallback;
@@ -28,26 +32,24 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import junit.framework.TestCase;
-
-public class CameraTestCase extends TestCase {
+public class CameraPerformanceTestHelper {
     private static final String TAG = "CameraTestCase";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
-    protected static final int NO_ERROR = -1;
-    protected static final long WAIT_FOR_COMMAND_TO_COMPLETE_NS = 5000000000L;
-    protected static final long WAIT_FOR_FOCUS_TO_COMPLETE_NS = 5000000000L;
-    protected static final long WAIT_FOR_SNAPSHOT_TO_COMPLETE_NS = 5000000000L;
-    protected Looper mLooper = null;
+    public static final int NO_ERROR = -1;
+    public static final long WAIT_FOR_COMMAND_TO_COMPLETE_NS = 5000000000L;
+    public static final long WAIT_FOR_FOCUS_TO_COMPLETE_NS = 5000000000L;
+    public static final long WAIT_FOR_SNAPSHOT_TO_COMPLETE_NS = 5000000000L;
 
-    protected int mCameraErrorCode;
-    protected Camera mCamera;
+    private Looper mLooper = null;
+    private int mCameraErrorCode;
+    private Camera mCamera;
 
     /**
      * Initializes the message looper so that the Camera object can
      * receive the callback messages.
      */
-    protected void initializeMessageLooper(final int cameraId) throws InterruptedException {
+    public void initializeMessageLooper(final int cameraId) throws InterruptedException {
         Lock startLock = new ReentrantLock();
         Condition startDone = startLock.newCondition();
         mCameraErrorCode = NO_ERROR;
@@ -80,9 +82,9 @@
 
         startLock.lock();
         try {
-            if (startDone.awaitNanos(WAIT_FOR_COMMAND_TO_COMPLETE_NS) <= 0L) {
-                fail("initializeMessageLooper: start timeout");
-            }
+            assertTrue(
+                    "initializeMessageLooper: start timeout",
+                    startDone.awaitNanos(WAIT_FOR_COMMAND_TO_COMPLETE_NS) > 0L);
         } finally {
             startLock.unlock();
         }
@@ -93,7 +95,7 @@
     /**
      * Terminates the message looper thread, optionally allowing evict error
      */
-    protected void terminateMessageLooper() throws Exception {
+    public void terminateMessageLooper() throws Exception {
         mLooper.quit();
         // Looper.quit() is asynchronous. The looper may still has some
         // preview callbacks in the queue after quit is called. The preview
@@ -110,7 +112,7 @@
      * Start preview and wait for the first preview callback, which indicates the
      * preview becomes active.
      */
-    protected void startPreview() throws InterruptedException {
+    public void startPreview() throws InterruptedException {
         Lock previewLock = new ReentrantLock();
         Condition previewDone = previewLock.newCondition();
 
@@ -126,9 +128,9 @@
 
         previewLock.lock();
         try {
-            if (previewDone.awaitNanos(WAIT_FOR_COMMAND_TO_COMPLETE_NS) <= 0L) {
-                fail("Preview done timeout");
-            }
+            assertTrue(
+                    "Preview done timeout",
+                    previewDone.awaitNanos(WAIT_FOR_COMMAND_TO_COMPLETE_NS) > 0L);
         } finally {
             previewLock.unlock();
         }
@@ -139,7 +141,7 @@
     /**
      * Trigger and wait for autofocus to complete.
      */
-    protected void autoFocus() throws InterruptedException {
+    public void autoFocus() throws InterruptedException {
         Lock focusLock = new ReentrantLock();
         Condition focusDone = focusLock.newCondition();
 
@@ -154,9 +156,9 @@
 
         focusLock.lock();
         try {
-            if (focusDone.awaitNanos(WAIT_FOR_FOCUS_TO_COMPLETE_NS) <= 0L) {
-                fail("Autofocus timeout");
-            }
+            assertTrue(
+                    "Autofocus timeout",
+                    focusDone.awaitNanos(WAIT_FOR_FOCUS_TO_COMPLETE_NS) > 0L);
         } finally {
             focusLock.unlock();
         }
@@ -165,34 +167,35 @@
     /**
      * Trigger and wait for snapshot to finish.
      */
-    protected void takePicture() throws InterruptedException {
+    public void takePicture() throws InterruptedException {
         Lock snapshotLock = new ReentrantLock();
         Condition snapshotDone = snapshotLock.newCondition();
 
         mCamera.takePicture(/*shutterCallback*/ null, /*rawPictureCallback*/ null,
                 new PictureCallback() {
-            @Override
-            public void onPictureTaken(byte[] rawData, Camera camera) {
-                snapshotLock.lock();
-                try {
-                    if (rawData == null) {
-                        fail("Empty jpeg data");
+                    @Override
+                    public void onPictureTaken(byte[] rawData, Camera camera) {
+                        snapshotLock.lock();
+                        try {
+                            assertNotNull("Empty jpeg data", rawData);
+                            snapshotDone.signal();
+                        } finally {
+                            snapshotLock.unlock();
+                        }
                     }
-                    snapshotDone.signal();
-                } finally {
-                    snapshotLock.unlock();
-                }
-            }
-        });
+                });
 
         snapshotLock.lock();
         try {
-            if (snapshotDone.awaitNanos(WAIT_FOR_SNAPSHOT_TO_COMPLETE_NS) <= 0L) {
-                fail("TakePicture timeout");
-            }
+            assertTrue(
+                    "TakePicture timeout",
+                    snapshotDone.awaitNanos(WAIT_FOR_SNAPSHOT_TO_COMPLETE_NS) > 0L);
         } finally {
             snapshotLock.unlock();
         }
     }
 
-}
+    public Camera getCamera() {
+        return mCamera;
+    }
+}
\ No newline at end of file
diff --git a/tests/camera/src/android/hardware/cts/LegacyCameraPerformanceTest.java b/tests/camera/src/android/hardware/cts/LegacyCameraPerformanceTest.java
index 74ffdff..ac3f6dd 100644
--- a/tests/camera/src/android/hardware/cts/LegacyCameraPerformanceTest.java
+++ b/tests/camera/src/android/hardware/cts/LegacyCameraPerformanceTest.java
@@ -30,33 +30,41 @@
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.compatibility.common.util.Stat;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
 import java.util.Arrays;
 
 /**
  * Measure and report legacy camera device performance.
  */
-public class LegacyCameraPerformanceTest extends CameraTestCase {
+@RunWith(JUnit4.class)
+public class LegacyCameraPerformanceTest {
     private static final String TAG = "CameraPerformanceTest";
     private static final String REPORT_LOG_NAME = "CtsCamera1TestCases";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
     private Instrumentation mInstrumentation;
+    private CameraPerformanceTestHelper mHelper;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mHelper = new CameraPerformanceTestHelper();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        if (mCamera != null) {
-            mCamera.release();
-            mCamera = null;
+    @After
+    public void tearDown() throws Exception {
+        if (mHelper.getCamera() != null) {
+            mHelper.getCamera().release();
+
         }
     }
 
+    @Test
     public void testLegacyApiPerformance() throws Exception {
         final int NUM_TEST_LOOPS = 10;
 
@@ -75,14 +83,14 @@
             double[] cameraAutoFocusTimes = new double[NUM_TEST_LOOPS];
             boolean afSupported = false;
             long openTimeMs, startPreviewTimeMs, stopPreviewTimeMs, closeTimeMs, takePictureTimeMs,
-                 autofocusTimeMs;
+                    autofocusTimeMs;
 
             for (int i = 0; i < NUM_TEST_LOOPS; i++) {
                 openTimeMs = SystemClock.elapsedRealtime();
-                initializeMessageLooper(id);
+                mHelper.initializeMessageLooper(id);
                 cameraOpenTimes[i] = SystemClock.elapsedRealtime() - openTimeMs;
 
-                Parameters parameters = mCamera.getParameters();
+                Parameters parameters = mHelper.getCamera().getParameters();
                 if (i == 0) {
                     for (String focusMode: parameters.getSupportedFocusModes()) {
                         if (Parameters.FOCUS_MODE_AUTO.equals(focusMode)) {
@@ -94,18 +102,18 @@
 
                 if (afSupported) {
                     parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
-                    mCamera.setParameters(parameters);
+                    mHelper.getCamera().setParameters(parameters);
                 }
 
                 SurfaceTexture previewTexture = new SurfaceTexture(/*random int*/ 1);
-                mCamera.setPreviewTexture(previewTexture);
+                mHelper.getCamera().setPreviewTexture(previewTexture);
                 startPreviewTimeMs = SystemClock.elapsedRealtime();
-                startPreview();
+                mHelper.startPreview();
                 startPreviewTimes[i] = SystemClock.elapsedRealtime() - startPreviewTimeMs;
 
                 if (afSupported) {
                     autofocusTimeMs = SystemClock.elapsedRealtime();
-                    autoFocus();
+                    mHelper.autoFocus();
                     cameraAutoFocusTimes[i] = SystemClock.elapsedRealtime() - autofocusTimeMs;
                 }
 
@@ -113,18 +121,18 @@
                 Thread.sleep(1000);
 
                 takePictureTimeMs = SystemClock.elapsedRealtime();
-                takePicture();
+                mHelper.takePicture();
                 cameraTakePictureTimes[i] = SystemClock.elapsedRealtime() - takePictureTimeMs;
 
                 //Resume preview after image capture
-                startPreview();
+                mHelper.startPreview();
 
                 stopPreviewTimeMs = SystemClock.elapsedRealtime();
-                mCamera.stopPreview();
+                mHelper.getCamera().stopPreview();
                 closeTimeMs = SystemClock.elapsedRealtime();
                 stopPreviewTimes[i] = closeTimeMs - stopPreviewTimeMs;
 
-                terminateMessageLooper();
+                mHelper.terminateMessageLooper();
                 cameraCloseTimes[i] = SystemClock.elapsedRealtime() - closeTimeMs;
                 previewTexture.release();
             }
@@ -192,4 +200,4 @@
             reportLog.submit(mInstrumentation);
         }
     }
-}
+}
\ No newline at end of file
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 33f9346..d9fdcfb 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
@@ -25,7 +25,7 @@
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.cts.CameraTestUtils;
 import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
 import android.util.Range;
 import android.util.Size;
 import android.util.Log;
@@ -1816,6 +1816,26 @@
         return maxZoom;
     }
 
+    public Range<Float> getZoomRatioRangeChecked() {
+        Key<Range<Float>> key =
+                CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE;
+
+        Range<Float> zoomRatioRange = getValueFromKeyNonNull(key);
+        if (zoomRatioRange == null) {
+            return new Range<Float>(1.0f, 1.0f);
+        }
+
+        checkTrueForKey(key, String.format(" min zoom ratio %f should be no more than 1",
+                zoomRatioRange.getLower()), zoomRatioRange.getLower() <= 1.0);
+        checkTrueForKey(key, String.format(" max zoom ratio %f should be no less than 1",
+                zoomRatioRange.getUpper()), zoomRatioRange.getUpper() >= 1.0);
+        final float ZOOM_MIN_RANGE = 0.01f;
+        checkTrueForKey(key, " zoom ratio range should be reasonably large",
+                zoomRatioRange.getUpper().equals(zoomRatioRange.getLower()) ||
+                zoomRatioRange.getUpper() - zoomRatioRange.getLower() > ZOOM_MIN_RANGE);
+        return zoomRatioRange;
+    }
+
     public int[] getAvailableSceneModesChecked() {
         Key<int[]> key =
                 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
@@ -1853,21 +1873,21 @@
         return modes;
     }
 
-    public CapabilityAndMaxSize[] getAvailableBokehCapsChecked() {
+    public Capability[] getAvailableBokehCapsChecked() {
         final Size FULL_HD = new Size(1920, 1080);
         Rect activeRect = getValueFromKeyNonNull(
                 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-        Key<CapabilityAndMaxSize[]> key =
+        Key<Capability[]> key =
                 CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES;
-        CapabilityAndMaxSize[] caps = mCharacteristics.get(key);
+        Capability[] caps = mCharacteristics.get(key);
         if (caps == null) {
-            return new CapabilityAndMaxSize[0];
+            return new Capability[0];
         }
 
         Size[] yuvSizes = getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888,
                 StaticMetadata.StreamDirection.Output);
         List<Size> yuvSizesList = Arrays.asList(yuvSizes);
-        for (CapabilityAndMaxSize cap : caps) {
+        for (Capability cap : caps) {
             int bokehMode = cap.getMode();
             Size maxStreamingSize = cap.getMaxStreamingSize();
             boolean maxStreamingSizeIsZero =
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java
index 85d0474..7e1e303 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java
@@ -49,6 +49,7 @@
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.lessThanOrEqualTo;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
@@ -76,6 +77,7 @@
 import java.util.List;
 import java.util.Queue;
 import java.util.concurrent.TimeUnit;
+import java.util.function.IntConsumer;
 
 /**
  * CTS device tests for {@link com.android.server.wm.ActivityMetricsLogger}.
@@ -85,6 +87,7 @@
 @Presubmit
 public class ActivityMetricsLoggerTests extends ActivityManagerTestBase {
     private static final String TAG_ATM = "ActivityTaskManager";
+    private static final int EVENT_WM_ACTIVITY_LAUNCH_TIME = 30009;
     private final MetricsReader mMetricsReader = new MetricsReader();
     private long mPreUptimeMs;
     private LogSeparator mLogSeparator;
@@ -112,7 +115,7 @@
         final LogMaker metricsLog = getMetricsLog(TEST_ACTIVITY, APP_TRANSITION);
         final String[] deviceLogs = getDeviceLogsForComponents(mLogSeparator, TAG_ATM);
         final List<Event> eventLogs = getEventLogsForComponents(mLogSeparator,
-                30009 /* AM_ACTIVITY_LAUNCH_TIME */);
+                EVENT_WM_ACTIVITY_LAUNCH_TIME);
 
         final long postUptimeMs = SystemClock.uptimeMillis();
         assertMetricsLogs(TEST_ACTIVITY, APP_TRANSITION, metricsLog, mPreUptimeMs, postUptimeMs);
@@ -158,18 +161,24 @@
 
     private void assertEventLogsContainsLaunchTime(List<Event> events, ComponentName componentName,
             int windowsDrawnDelayMs) {
-        for (Event event : events) {
-            Object[] arr = (Object[]) event.getData();
+        verifyLaunchTimeEventLogs(events, componentName,
+                delay -> assertEquals("Unexpected windows drawn delay for " + componentName,
+                        delay, windowsDrawnDelayMs));
+    }
+
+    private void verifyLaunchTimeEventLogs(List<Event> launchTimeEvents,
+            ComponentName componentName, IntConsumer launchTimeVerifier) {
+        for (Event event : launchTimeEvents) {
+            final Object[] arr = (Object[]) event.getData();
             assertEquals(4, arr.length);
             final String name = (String) arr[2];
-            final int delay = (int) arr[3];
+            final int launchTime = (int) arr[3];
             if (name.equals(componentName.flattenToShortString())) {
-                assertEquals("Unexpected windows drawn delay for " + componentName,
-                        delay, windowsDrawnDelayMs);
+                launchTimeVerifier.accept(launchTime);
                 return;
             }
         }
-        fail("Could not find am_activity_launch_time for " + componentName);
+        fail("Could not find wm_activity_launch_time for " + componentName);
     }
 
     /**
@@ -403,6 +412,18 @@
                         postUptimeMs);
     }
 
+    @Test
+    public void testLaunchTimeEventLogNonProcessSwitch() {
+        launchAndWaitForActivity(SINGLE_TASK_ACTIVITY);
+        mLogSeparator = separateLogs();
+
+        // Launch another activity in the same process.
+        launchAndWaitForActivity(TEST_ACTIVITY);
+        final List<Event> eventLogs = getEventLogsForComponents(mLogSeparator,
+                EVENT_WM_ACTIVITY_LAUNCH_TIME);
+        verifyLaunchTimeEventLogs(eventLogs, TEST_ACTIVITY, time -> assertNotEquals(0, time));
+    }
+
     private void launchAndWaitForActivity(ComponentName activity) {
         getLaunchActivityBuilder()
                 .setUseInstrumentation()
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
index 01b48b5..6067a13 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
@@ -29,7 +29,7 @@
 import android.content.res.Configuration;
 import android.hardware.display.DisplayManager;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.util.Size;
 import android.view.Display;
 
@@ -50,8 +50,8 @@
      */
     @Test
     public void testDefaultDisplayOverrideConfiguration() throws Exception {
-        final List<ActivityDisplay> reportedDisplays = getDisplaysStates();
-        final ActivityDisplay primaryDisplay = getDisplayState(reportedDisplays, DEFAULT_DISPLAY);
+        final List<DisplayContent> reportedDisplays = getDisplaysStates();
+        final DisplayContent primaryDisplay = getDisplayState(reportedDisplays, DEFAULT_DISPLAY);
         assertEquals("Primary display's configuration should be equal to global configuration.",
                 primaryDisplay.mOverrideConfiguration, primaryDisplay.mFullConfiguration);
         assertEquals("Primary display's configuration should be equal to global configuration.",
@@ -63,7 +63,7 @@
      */
     @Test
     public void testCreateVirtualDisplayWithCustomConfig() throws Exception {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
 
         // Find the density of created display.
         final int newDensityDpi = newDisplay.mFullConfiguration.densityDpi;
@@ -99,7 +99,7 @@
         assumeFalse(supportsMultiDisplay());
 
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
 
         // Launch activity on new secondary display.
         launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
@@ -121,7 +121,7 @@
 
     @Test
     public void testCreateMultipleVirtualDisplays() throws Exception {
-        final List<ActivityDisplay> originalDs = getDisplaysStates();
+        final List<DisplayContent> originalDs = getDisplaysStates();
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             // Create new virtual displays
             virtualDisplaySession.createDisplays(3);
@@ -179,11 +179,11 @@
                 (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
 
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
-            final ActivityDisplay activityDisplay = virtualDisplaySession
+            final DisplayContent displayContent = virtualDisplaySession
                     .setSimulateDisplay(true)
                     .setSimulationDisplaySize(displayWidth, displayHeight)
                     .createDisplay();
-            final Display display = displayManager.getDisplay(activityDisplay.mId);
+            final Display display = displayManager.getDisplay(displayContent.mId);
             Configuration config = context.createDisplayContext(display)
                     .getResources().getConfiguration();
             return config;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
index 0004b78..32e5ff8 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
@@ -353,7 +353,7 @@
 
         final int displayId = mAmWmState.getAmState()
                 .getDisplayByActivity(SHOW_WHEN_LOCKED_ATTR_ROTATION_ACTIVITY);
-        ActivityManagerState.ActivityDisplay display = mAmWmState.getAmState()
+        ActivityManagerState.DisplayContent display = mAmWmState.getAmState()
                 .getDisplay(displayId);
         final int origDisplayOrientation = display.mFullConfiguration.orientation;
         final int orientation = origDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
index 5f144d7..ef3f2fb 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
@@ -64,7 +64,7 @@
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.server.wm.ActivityManagerState.ActivityStack;
 import android.server.wm.CommandSession.ActivitySession;
 import android.server.wm.CommandSession.SizeInfo;
@@ -117,7 +117,7 @@
 
     private void validateActivityLaunchOnNewDisplay(int activityType) {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch activity on new secondary display.
@@ -167,7 +167,7 @@
                 .setTargetActivity(TEST_ACTIVITY).setNewTask(true)
                 .setDisplayId(DEFAULT_DISPLAY).execute();
 
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
         final int newDisplayId = newDisplay.mId;
@@ -211,7 +211,7 @@
         assertEquals("Unexpected resumed activity",
                 0, mAmWmState.getAmState().getResumedActivitiesCount());
 
-        final ActivityDisplay newDisplay = externalDisplaySession
+        final DisplayContent newDisplay = externalDisplaySession
                 .setCanShowWithInsecureKeyguard(true).createVirtualDisplay();
 
         launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
@@ -230,7 +230,7 @@
     @Test
     public void testLaunchNonResizeableActivityOnSecondaryDisplay() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch activity on new secondary display.
@@ -261,7 +261,7 @@
         final VirtualDisplayLauncher virtualLauncher =
                 mObjectTracker.manage(new VirtualDisplayLauncher());
         // Create new virtual display.
-        final ActivityDisplay newDisplay = virtualLauncher
+        final DisplayContent newDisplay = virtualLauncher
                 .setSimulateDisplay(true).createDisplay();
         // Launch a non-resizeable activity on a primary display.
         final ActivitySession nonResizeableSession = virtualLauncher.launchActivity(
@@ -297,7 +297,7 @@
     @Test
     public void testLaunchNonResizeableActivityFromSecondaryDisplaySameTask() {
         // Create new simulated display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -319,7 +319,7 @@
     @Test
     public void testLaunchNonResizeableActivityFromSecondaryDisplayNewTask() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch activity on new secondary display.
@@ -356,7 +356,7 @@
     @Test
     public void testConsequentLaunchActivity() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch activity on new secondary display.
@@ -382,7 +382,7 @@
     @Test
     public void testConsequentLaunchActivityFromSecondaryDisplay() {
         // Create new simulated display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -407,7 +407,7 @@
     @Test
     public void testConsequentLaunchActivityFromVirtualDisplay() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch activity on new secondary display.
@@ -432,7 +432,7 @@
     @Test
     public void testConsequentLaunchActivityFromVirtualDisplayToTargetDisplay() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch activity on new secondary display.
@@ -473,7 +473,7 @@
         launchActivity(LAUNCHING_ACTIVITY);
 
         // Create new simulated display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -493,7 +493,7 @@
     public void testLaunchPendingActivityOnSecondaryDisplay() {
         pressHomeButton();
         // Create new simulated display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
         final Bundle bundle = ActivityOptions.makeBasic().
@@ -537,7 +537,7 @@
         launchActivity(LAUNCHING_ACTIVITY);
 
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
         // Launch something to that display so that a new stack is created. We need this to be
         // able to compare task numbers in stacks later.
@@ -586,7 +586,7 @@
         launchActivity(RESIZEABLE_ACTIVITY);
 
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
         final int stackNum = mAmWmState.getAmState().getDisplay(DEFAULT_DISPLAY).mStacks.size();
@@ -617,7 +617,7 @@
      */
     @Test
     public void testTaskMatchAcrossDisplays() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
@@ -676,7 +676,7 @@
                 .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY).setNewTask(true)
                 .setDisplayId(DEFAULT_DISPLAY).execute();
 
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         getLaunchActivityBuilder().setUseInstrumentation().setWithShellPermission(true)
                 .setTargetActivity(TEST_ACTIVITY).setNewTask(true)
                 .setDisplayId(newDisplay.mId).execute();
@@ -694,7 +694,7 @@
      */
     @Test
     public void testLaunchDisplayAffinityMatch() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
@@ -733,7 +733,7 @@
      */
     @Test
     public void testNewTaskSameDisplay() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -769,7 +769,7 @@
     @Test
     public void testImmediateLaunchOnNewDisplay() {
         // Create new virtual display and immediately launch an activity on it.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setLaunchActivity(TEST_ACTIVITY)
                 .createDisplay();
 
@@ -785,7 +785,7 @@
     /** Tests launching of activities on a single task instance display. */
     @Test
     public void testSingleTaskInstanceDisplay() {
-        ActivityDisplay display = createManagedVirtualDisplaySession()
+        DisplayContent display = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
         final int displayId = display.mId;
@@ -822,7 +822,7 @@
     public void testLaunchPendingIntentActivity() throws Exception {
         final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
 
-        final ActivityDisplay activityDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent displayContent = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -834,9 +834,9 @@
         final int resultCode = 1;
         // Activity should be launched on target display according to the caller context.
         final Context displayContext =
-                mContext.createDisplayContext(displayManager.getDisplay(activityDisplay.mId));
+                mContext.createDisplayContext(displayManager.getDisplay(displayContent.mId));
         getPendingIntentActivity(TOP_ACTIVITY).send(displayContext, resultCode, null /* intent */);
-        waitAndAssertTopResumedActivity(TOP_ACTIVITY, activityDisplay.mId,
+        waitAndAssertTopResumedActivity(TOP_ACTIVITY, displayContent.mId,
                 "Activity launched on secondary display and on top");
 
         // Activity should be brought to front on the same display if it already existed.
@@ -846,11 +846,11 @@
 
         // Activity should be moved to target display.
         final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchDisplayId(activityDisplay.mId);
+        options.setLaunchDisplayId(displayContent.mId);
         getPendingIntentActivity(TEST_ACTIVITY).send(mContext, resultCode, null /* intent */,
                 null /* onFinished */, null /* handler */, null /* requiredPermission */,
                 options.toBundle());
-        waitAndAssertTopResumedActivity(TEST_ACTIVITY, activityDisplay.mId,
+        waitAndAssertTopResumedActivity(TEST_ACTIVITY, displayContent.mId,
                 "Activity launched on secondary display and on top");
     }
 
@@ -873,7 +873,7 @@
         // Start TEST_ACTIVITY on top of LAUNCHING_ACTIVITY within the same task
         getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute();
 
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
index 4ab381c..7cbdcd4 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
@@ -40,7 +40,7 @@
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.view.Display;
 import android.view.View;
 import android.view.WindowManager;
@@ -100,7 +100,7 @@
         waitAndAssertResume(activityName);
 
         // Create new simulated display
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -157,7 +157,7 @@
         assertImeShownAndMatchesDisplayId(
                 activityClass, mockImeSession, DEFAULT_DISPLAY);
 
-        final ActivityDisplay newDisplay = virtualDisplaySession
+        final DisplayContent newDisplay = virtualDisplaySession
                 .setSimulateDisplay(true).setShowSystemDecorations(true).createDisplay();
 
         // Launch activity on the secondary display and make IME show.
@@ -190,7 +190,7 @@
     @Test
     public void testInputMethodManagerDisplayId() {
         // Create a simulated display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -215,7 +215,7 @@
     private void testViewGetDisplay(boolean isPrimary) {
         final TestActivitySession<ClientTestActivity> activitySession =
                 createManagedTestActivitySession();
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
         final int displayId = isPrimary ? DEFAULT_DISPLAY : newDisplay.mId;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java
index 780712a..56949d8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java
@@ -25,7 +25,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -58,7 +58,7 @@
     @Test
     public void testDismissKeyguardActivity_secondaryDisplay() {
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
 
         lockScreenSession.gotoKeyguard();
         mAmWmState.assertKeyguardShowingAndNotOccluded();
@@ -75,7 +75,7 @@
     @Test
     public void testShowKeyguardDialogOnSecondaryDisplay() {
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
-        final ActivityDisplay publicDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent publicDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
 
@@ -101,9 +101,9 @@
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         final VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
 
-        final ActivityDisplay privateDisplay =
+        final DisplayContent privateDisplay =
                 virtualDisplaySession.setPublicDisplay(false).createDisplay();
-        final ActivityDisplay publicDisplay =
+        final DisplayContent publicDisplay =
                 virtualDisplaySession.setPublicDisplay(true).createDisplay();
 
         lockScreenSession.gotoKeyguard();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java
index 590ff27..2e034c0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java
@@ -27,7 +27,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 
 import androidx.test.filters.FlakyTest;
 
@@ -62,7 +62,7 @@
         lockScreenSession.setLockCredential();
 
         // Create new usual virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
@@ -96,7 +96,7 @@
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         lockScreenSession.setLockCredential();
 
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(false)
                 .createDisplay();
         launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
@@ -117,7 +117,7 @@
                 mObjectTracker.manage(new LockScreenSession(FLAG_REMOVE_ACTIVITIES_ON_CLOSE));
         lockScreenSession.setLockCredential();
 
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
 
@@ -142,7 +142,7 @@
                 mObjectTracker.manage(new LockScreenSession(FLAG_REMOVE_ACTIVITIES_ON_CLOSE));
         lockScreenSession.setLockCredential();
 
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
index 0d61322..69d599e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
@@ -48,7 +48,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.server.wm.ActivityManagerState.ActivityStack;
 import android.server.wm.CommandSession.ActivityCallback;
 import android.server.wm.CommandSession.ActivitySession;
@@ -80,7 +80,7 @@
     public void testContentDestroyOnDisplayRemoved() {
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             // Create new private virtual display.
-            final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
+            final DisplayContent newDisplay = virtualDisplaySession.createDisplay();
             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
             // Launch activities on new secondary display.
@@ -121,7 +121,7 @@
     public void testActivityLaunchOnContentDestroyDisplayRemoved() {
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             // Create new private virtual display.
-            final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
+            final DisplayContent newDisplay = virtualDisplaySession.createDisplay();
             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
             // Launch activities on new secondary display.
@@ -144,7 +144,7 @@
     public void testDisplayResize() {
         final VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
         // Create new virtual display.
-        final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
+        final DisplayContent newDisplay = virtualDisplaySession.createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
         // Launch a resizeable activity on new secondary display.
@@ -196,7 +196,7 @@
         final VirtualDisplayLauncher virtualLauncher =
                 mObjectTracker.manage(new VirtualDisplayLauncher());
         // Create new virtual display.
-        final ActivityDisplay newDisplay = virtualLauncher.setResizeDisplay(false).createDisplay();
+        final DisplayContent newDisplay = virtualLauncher.setResizeDisplay(false).createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
         // Launch activity on new secondary display.
@@ -247,7 +247,7 @@
         waitAndAssertTopResumedActivity(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY,
                 "Activity launched on primary display must be resumed");
 
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .setCanShowWithInsecureKeyguard(true).createVirtualDisplay();
 
         launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
@@ -283,7 +283,7 @@
     @Test
     public void testExternalDisplayToggleState() {
         final ExternalDisplaySession externalDisplaySession = createManagedExternalDisplaySession();
-        final ActivityDisplay newDisplay = externalDisplaySession.createVirtualDisplay();
+        final DisplayContent newDisplay = externalDisplaySession.createVirtualDisplay();
 
         launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
 
@@ -321,7 +321,7 @@
         mAmWmState.getAmState().computeState();
         final int displayCount = mAmWmState.getAmState().getDisplayCount();
         try (final VirtualDisplaySession externalDisplaySession = new VirtualDisplaySession()) {
-            final ActivityDisplay newDisplay = externalDisplaySession
+            final DisplayContent newDisplay = externalDisplaySession
                     .setSimulateDisplay(true).createDisplay();
             launchActivityOnDisplay(VIRTUAL_DISPLAY_ACTIVITY, newDisplay.mId);
             waitAndAssertTopResumedActivity(VIRTUAL_DISPLAY_ACTIVITY, newDisplay.mId,
@@ -346,7 +346,7 @@
         launchActivity(LAUNCHING_ACTIVITY);
 
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
         // Launch activity on new secondary display.
@@ -370,7 +370,7 @@
     @Test
     public void testMoveTaskBetweenDisplays() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
         mAmWmState.assertFocusedActivity("Virtual display activity must be on top",
                 VIRTUAL_DISPLAY_ACTIVITY);
@@ -457,7 +457,7 @@
     private void tryCreatingAndRemovingDisplayWithActivity(boolean splitScreen, int windowingMode) {
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             // Create new virtual display.
-            final ActivityDisplay newDisplay = virtualDisplaySession
+            final DisplayContent newDisplay = virtualDisplaySession
                     .setPublicDisplay(true)
                     .setLaunchInSplitScreen(splitScreen)
                     .createDisplay();
@@ -516,7 +516,7 @@
     private void validateStackFocusSwitchOnStackEmptied(VirtualDisplaySession virtualDisplaySession,
             LockScreenSession lockScreenSession) {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
+        final DisplayContent newDisplay = virtualDisplaySession.createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
         // Launch activity on new secondary display.
@@ -551,7 +551,7 @@
         assumeFalse(perDisplayFocusEnabled());
 
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
 
         mAmWmState.computeState(VIRTUAL_DISPLAY_ACTIVITY);
         mAmWmState.assertFocusedActivity("Top activity must be the latest launched one",
@@ -598,7 +598,7 @@
         assertEquals("Unexpected resumed activity",
                 0, mAmWmState.getAmState().getResumedActivitiesCount());
 
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .setCanShowWithInsecureKeyguard(true).createVirtualDisplay();
 
         launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
@@ -636,7 +636,7 @@
 
         launchActivity(TEST_ACTIVITY);
 
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .createVirtualDisplay();
         launchActivityOnDisplay(SHOW_WHEN_LOCKED_ATTR_ACTIVITY, newDisplay.mId);
 
@@ -658,7 +658,7 @@
         launchActivity(TEST_ACTIVITY);
         mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
 
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
         launchActivityOnDisplay(VIRTUAL_DISPLAY_ACTIVITY, newDisplay.mId);
         waitAndAssertTopResumedActivity(VIRTUAL_DISPLAY_ACTIVITY, newDisplay.mId,
@@ -689,7 +689,7 @@
      */
     @Test
     public void testSecondaryDisplayShowToast() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
         final String TOAST_NAME = "Toast";
@@ -711,7 +711,7 @@
     public void testTaskSurfaceSizeAfterReparentDisplay() {
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             // Create new simulated display and launch an activity on it.
-            final ActivityDisplay newDisplay = virtualDisplaySession.setSimulateDisplay(true)
+            final DisplayContent newDisplay = virtualDisplaySession.setSimulateDisplay(true)
                     .createDisplay();
             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
 
@@ -749,7 +749,7 @@
         final TestActivitySession<StandardActivity> transitionActivitySession =
                 createManagedTestActivitySession();
         // Create new simulated display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch BottomActivity on top of launcher activity to prevent transition state
@@ -783,7 +783,7 @@
     @Test
     public void testNoTransitionWhenMovingActivityToDisplay() throws Exception {
         // Create new simulated display & capture new display's transition state.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         // Launch TestActivity in virtual display & capture its transition state.
@@ -809,7 +809,7 @@
 
     @Test
     public void testPreQTopProcessResumedActivity() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).createDisplay();
 
         getLaunchActivityBuilder().setUseInstrumentation()
@@ -839,4 +839,28 @@
                 mAmWmState.getAmState().getResumedActivitiesCountInPackage(
                         SDK_27_TEST_ACTIVITY.getPackageName()));
     }
+
+    @Test
+    public void testPreQTopProcessResumedDisplayMoved() throws Exception {
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
+                .setSimulateDisplay(true).createDisplay();
+        getLaunchActivityBuilder().setUseInstrumentation()
+                .setTargetActivity(SDK_27_LAUNCHING_ACTIVITY).setNewTask(true)
+                .setDisplayId(DEFAULT_DISPLAY).execute();
+        waitAndAssertTopResumedActivity(SDK_27_LAUNCHING_ACTIVITY, DEFAULT_DISPLAY,
+                "Activity launched on default display must be resumed and focused");
+
+        getLaunchActivityBuilder().setUseInstrumentation()
+                .setTargetActivity(SDK_27_TEST_ACTIVITY).setNewTask(true)
+                .setDisplayId(newDisplay.mId).execute();
+        waitAndAssertTopResumedActivity(SDK_27_TEST_ACTIVITY, newDisplay.mId,
+                "Activity launched on secondary display must be resumed and focused");
+
+        tapOnDisplayCenter(DEFAULT_DISPLAY);
+        waitAndAssertTopResumedActivity(SDK_27_LAUNCHING_ACTIVITY, DEFAULT_DISPLAY,
+                "Activity launched on default display must be resumed and focused");
+        assertEquals("There must be only one resumed activity in the package.", 1,
+                mAmWmState.getAmState().getResumedActivitiesCountInPackage(
+                        SDK_27_LAUNCHING_ACTIVITY.getPackageName()));
+    }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPrivateDisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPrivateDisplayTests.java
index 0ba5526..93b1efa 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPrivateDisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPrivateDisplayTests.java
@@ -28,7 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.server.wm.WindowManagerState.Display;
 import android.util.Log;
 
@@ -70,8 +70,8 @@
         mPrivateDisplayIds.clear();
         mAmWmState.computeState(true);
 
-        for (ActivityDisplay activityDisplay: getDisplaysStates()) {
-            int displayId = activityDisplay.mId;
+        for (DisplayContent displayContent: getDisplaysStates()) {
+            int displayId = displayContent.mId;
             Display display = mAmWmState.getWmState().getDisplay(displayId);
             if ((display.getFlags() & FLAG_PRIVATE) != 0) {
                 mPrivateDisplayIds.add(displayId);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
index 646d1ed..f45ec03 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
@@ -63,7 +63,7 @@
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.server.wm.ActivityManagerState.ActivityStack;
 import android.server.wm.CommandSession.ActivitySession;
 import android.server.wm.TestJournalProvider.TestJournalContainer;
@@ -107,7 +107,7 @@
     @Test
     public void testLaunchWithoutPermissionOnVirtualDisplayByOwner() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
 
         // Try to launch an activity and check it security exception was triggered.
         getLaunchActivityBuilder()
@@ -135,7 +135,7 @@
     @Test
     public void testLaunchWithoutPermissionOnVirtualDisplay() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
 
         separateTestJournal();
 
@@ -161,7 +161,7 @@
     @Test
     public void testConsequentLaunchActivityFromVirtualDisplayNoEmbedding() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
 
         // Launch activity on new secondary display.
         launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
@@ -193,7 +193,7 @@
      */
     @Test
     public void testCanAccessSystemOwnedDisplay()  {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -207,7 +207,7 @@
      */
     @Test
     public void testCanAccessPublicVirtualDisplayWithInternalPermission() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
 
@@ -224,7 +224,7 @@
      */
     @Test
     public void testCanAccessPrivateVirtualDisplayWithInternalPermission() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(false)
                 .createDisplay();
 
@@ -242,7 +242,7 @@
      */
     @Test
     public void testCantAccessPublicVirtualDisplayNoEmbeddingPermission() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
 
@@ -256,7 +256,7 @@
      */
     @Test
     public void testCantAccessPublicVirtualDisplayActivityEmbeddingNotAllowed() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
 
@@ -273,7 +273,7 @@
      */
     @Test
     public void testCanAccessPublicVirtualDisplayActivityEmbeddingAllowed() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
 
@@ -290,7 +290,7 @@
      */
     @Test
     public void testCantAccessPrivateVirtualDisplay() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(false)
                 .createDisplay();
 
@@ -304,7 +304,7 @@
      */
     @Test
     public void testCanAccessPrivateVirtualDisplayByOwner() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(false)
                 .createDisplay();
 
@@ -327,7 +327,7 @@
      */
     @Test
     public void testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingAllowed() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(false)
                 .createDisplay();
         // Launch a test activity into the target display.
@@ -352,7 +352,7 @@
     @Test
     public void testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingNotAllowed()
             throws Exception {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(false)
                 .createDisplay();
         // Launch a test activity into the target display.
@@ -389,7 +389,7 @@
         final VirtualDisplayLauncher virtualDisplayLauncher =
                 mObjectTracker.manage(new VirtualDisplayLauncher());
         // Create a virtual private display.
-        final ActivityDisplay newDisplay = virtualDisplayLauncher
+        final DisplayContent newDisplay = virtualDisplayLauncher
                 .setPublicDisplay(false)
                 .createDisplay();
         // Launch an embeddable activity into the private display.
@@ -418,7 +418,7 @@
         final VirtualDisplayLauncher virtualDisplayLauncher =
                 mObjectTracker.manage(new VirtualDisplayLauncher());
         // Create a virtual private display.
-        final ActivityDisplay newDisplay = virtualDisplayLauncher
+        final DisplayContent newDisplay = virtualDisplayLauncher
                 .setPublicDisplay(false)
                 .createDisplay();
         // Launch an embeddable activity into the private display.
@@ -443,7 +443,7 @@
     @Test
     public void testDisplayHasAccess_ExceptionWhenAddViewWithoutPresentOnPrivateDisplay() {
         // Create a virtual private display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(false)
                 .createDisplay();
         try {
@@ -473,7 +473,7 @@
     @Test
     public void testPermissionLaunchFromShell(){
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
         mAmWmState.assertFocusedActivity("Virtual display activity must be on top",
                 VIRTUAL_DISPLAY_ACTIVITY);
@@ -507,7 +507,7 @@
     @Test
     public void testPermissionLaunchFromAppOnSecondary() {
         // Create new simulated display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -535,7 +535,7 @@
     /** Tests that an activity can launch an activity from a different UID into its own task. */
     @Test
     public void testPermissionLaunchMultiUidTask() {
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -565,7 +565,7 @@
     @Test
     public void testPermissionLaunchFromOwner() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
         mAmWmState.assertFocusedActivity("Virtual display activity must be focused",
                 VIRTUAL_DISPLAY_ACTIVITY);
@@ -602,7 +602,7 @@
     @Test
     public void testPermissionLaunchFromDifferentApp() {
         // Create new virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession().createDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay();
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
         mAmWmState.assertFocusedActivity("Virtual display activity must be focused",
                 VIRTUAL_DISPLAY_ACTIVITY);
@@ -636,7 +636,7 @@
     @Test
     public void testFlagShowWithInsecureKeyguardOnPublicVirtualDisplay() {
         // Try to create new show-with-insecure-keyguard public virtual display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .setCanShowWithInsecureKeyguard(true)
                 .setMustBeCreated(false)
@@ -653,7 +653,7 @@
     public void testSettingFlagWithoutInternalSystemPermission() throws Exception {
         // The reason to use a trusted display is that we can guarantee the security exception
         // is coming from lacking internal system permission.
-        final ActivityDisplay trustedDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent trustedDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
         final WindowManager wm = mTargetContext.getSystemService(WindowManager.class);
@@ -695,7 +695,7 @@
     public void testGettingFlagWithoutInternalSystemPermission() {
         // The reason to use a trusted display is that we can guarantee the security exception
         // is coming from lacking internal system permission.
-        final ActivityDisplay trustedDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent trustedDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
         final WindowManager wm = mTargetContext.getSystemService(WindowManager.class);
@@ -722,7 +722,7 @@
      */
     @Test
     public void testSettingFlagToUntrustedDisplay() throws Exception {
-        final ActivityDisplay untrustedDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent untrustedDisplay = createManagedVirtualDisplaySession()
                 .createDisplay();
         final WindowManager wm = mTargetContext.getSystemService(WindowManager.class);
 
@@ -767,7 +767,7 @@
      */
     @Test
     public void testGettingFlagFromUntrustedDisplay() {
-        final ActivityDisplay untrustedDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent untrustedDisplay = createManagedVirtualDisplaySession()
                 .createDisplay();
         final WindowManager wm = mTargetContext.getSystemService(WindowManager.class);
 
@@ -787,7 +787,7 @@
      */
     @Test
     public void testSettingFlagToTrustedDisplay() throws Exception {
-        final ActivityDisplay trustedDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent trustedDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
         final WindowManager wm = mTargetContext.getSystemService(WindowManager.class);
@@ -843,7 +843,7 @@
         final TestActivitySession<ImeTestActivity> imeTestActivitySession =
                 createManagedTestActivitySession();
          // Create a untrusted virtual display and assume the display should not show IME window.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true).createDisplay();
 
         // Launch Ime test activity in virtual display.
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index 1eb60c2..58fb32a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -53,7 +53,7 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.server.wm.TestJournalProvider.TestJournalContainer;
 import android.server.wm.WindowManagerState.Display;
 import android.server.wm.WindowManagerState.WindowState;
@@ -78,7 +78,6 @@
 
 import java.util.List;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
 
 /**
  * Build/Install/Run:
@@ -114,7 +113,7 @@
 
         TestJournalContainer.start();
 
-        final ActivityDisplay newDisplay = virtualDisplaySession
+        final DisplayContent newDisplay = virtualDisplaySession
                 .setSimulateDisplay(true).setShowSystemDecorations(true).createDisplay();
 
         wallpaperSession.setWallpaperComponent(TEST_LIVE_WALLPAPER_SERVICE);
@@ -131,10 +130,10 @@
     public void testWallpaperShowOnSecondaryDisplays()  {
         final ChangeWallpaperSession wallpaperSession = createManagedChangeWallpaperSession();
 
-        final ActivityDisplay untrustedDisplay = createManagedExternalDisplaySession()
+        final DisplayContent untrustedDisplay = createManagedExternalDisplaySession()
                 .setPublicDisplay(true).setShowSystemDecorations(true).createVirtualDisplay();
 
-        final ActivityDisplay decoredSystemDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent decoredSystemDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true).setShowSystemDecorations(true).createDisplay();
 
         final Bitmap tmpWallpaper = wallpaperSession.getTestBitmap();
@@ -202,7 +201,7 @@
     @Test
     public void testNavBarShowingOnDisplayWithDecor() {
         assumeHasBars();
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .setPublicDisplay(true).setShowSystemDecorations(true).createVirtualDisplay();
 
         mAmWmState.waitAndAssertNavBarShownOnDisplay(newDisplay.mId);
@@ -251,7 +250,7 @@
         // bars were added to a display that was added before executing this method that shouldn't
         // have nav bars (i.e. private or without system ui decor).
         try (final ExternalDisplaySession secondDisplaySession = new ExternalDisplaySession()) {
-            final ActivityDisplay supportsSysDecorDisplay = secondDisplaySession
+            final DisplayContent supportsSysDecorDisplay = secondDisplaySession
                     .setPublicDisplay(true).setShowSystemDecorations(true).createVirtualDisplay();
             mAmWmState.waitAndAssertNavBarShownOnDisplay(supportsSysDecorDisplay.mId);
             // This display has finished his task. Just close it.
@@ -278,7 +277,7 @@
         createManagedHomeActivitySession(SECONDARY_HOME_ACTIVITY);
 
         // Create new virtual display without system decoration support.
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .createVirtualDisplay();
 
         // Secondary home activity can't be launched on the display without system decoration
@@ -295,7 +294,7 @@
         createManagedHomeActivitySession(SINGLE_HOME_ACTIVITY);
 
         // Create new virtual display with system decoration support.
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .setShowSystemDecorations(true)
                 .createVirtualDisplay();
 
@@ -318,7 +317,7 @@
         createManagedHomeActivitySession(SINGLE_SECONDARY_HOME_ACTIVITY);
 
         // Create new virtual display with system decoration support.
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .setShowSystemDecorations(true)
                 .createVirtualDisplay();
 
@@ -342,7 +341,7 @@
         final VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
 
         // Create new virtual display with system decoration support.
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .setShowSystemDecorations(true)
                 .createVirtualDisplay();
 
@@ -366,7 +365,7 @@
         final VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
 
         // Create new virtual display with system decoration support.
-        final ActivityDisplay newDisplay = createManagedExternalDisplaySession()
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
                 .setShowSystemDecorations(true)
                 .createVirtualDisplay();
 
@@ -389,7 +388,7 @@
                 createManagedTestActivitySession();
 
         // Create a virtual display and launch an activity on it.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setShowSystemDecorations(true)
                 .setSimulateDisplay(true)
                 .createDisplay();
@@ -435,7 +434,7 @@
         final TestActivitySession<ImeTestActivityWithBrokenContextWrapper> imeTestActivitySession =
                 createManagedTestActivitySession();
         // Create a virtual display and launch an activity on it.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setShowSystemDecorations(true)
                 .setSimulateDisplay(true)
                 .createDisplay();
@@ -475,7 +474,7 @@
                 createManagedTestActivitySession();
 
         // Create a virtual display and launch an activity on virtual & default display.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setShowSystemDecorations(true)
                 .setSimulateDisplay(true)
                 .createDisplay();
@@ -531,7 +530,7 @@
                 createManagedTestActivitySession();
 
         // Create a virtual display by app and assume the display should not show IME window.
-        final ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setPublicDisplay(true)
                 .createDisplay();
         SystemUtil.runWithShellPermissionIdentity(
@@ -653,7 +652,7 @@
     }
 
     void assertImeWindowAndDisplayConfiguration(
-            WindowManagerState.WindowState imeWinState, ActivityDisplay display) {
+            WindowManagerState.WindowState imeWinState, DisplayContent display) {
         final Configuration configurationForIme = imeWinState.mMergedOverrideConfiguration;
         final Configuration configurationForDisplay =  display.mMergedOverrideConfiguration;
         final int displayDensityDpiForIme = configurationForIme.densityDpi;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
index 4886252..417115e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
@@ -53,7 +53,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.server.wm.CommandSession.ActivitySession;
 import android.server.wm.CommandSession.ActivitySessionClient;
 import android.server.wm.settings.SettingsSession;
@@ -99,12 +99,12 @@
         mTargetContext = getInstrumentation().getTargetContext();
     }
 
-    ActivityDisplay getDisplayState(int displayId) {
+    DisplayContent getDisplayState(int displayId) {
         return getDisplayState(getDisplaysStates(), displayId);
     }
 
-    ActivityDisplay getDisplayState(List<ActivityDisplay> displays, int displayId) {
-        for (ActivityDisplay display : displays) {
+    DisplayContent getDisplayState(List<DisplayContent> displays, int displayId) {
+        for (DisplayContent display : displays) {
             if (display.mId == displayId) {
                 return display;
             }
@@ -113,9 +113,9 @@
     }
 
     /** Return the display state with width, height, dpi. Always not default display. */
-    ActivityDisplay getDisplayState(List<ActivityDisplay> displays, int width, int height,
+    DisplayContent getDisplayState(List<DisplayContent> displays, int width, int height,
             int dpi) {
-        for (ActivityDisplay display : displays) {
+        for (DisplayContent display : displays) {
             if (display.mId == DEFAULT_DISPLAY) {
                 continue;
             }
@@ -128,17 +128,17 @@
         return null;
     }
 
-    List<ActivityDisplay> getDisplaysStates() {
+    List<DisplayContent> getDisplaysStates() {
         mAmWmState.getAmState().computeState();
         return mAmWmState.getAmState().getDisplays();
     }
 
     /** Find the display that was not originally reported in oldDisplays and added in newDisplays */
-    List<ActivityDisplay> findNewDisplayStates(List<ActivityDisplay> oldDisplays,
-            List<ActivityDisplay> newDisplays) {
-        final ArrayList<ActivityDisplay> result = new ArrayList<>();
+    List<DisplayContent> findNewDisplayStates(List<DisplayContent> oldDisplays,
+            List<DisplayContent> newDisplays) {
+        final ArrayList<DisplayContent> result = new ArrayList<>();
 
-        for (ActivityDisplay newDisplay : newDisplays) {
+        for (DisplayContent newDisplay : newDisplays) {
             if (oldDisplays.stream().noneMatch(d -> d.mId == newDisplay.mId)) {
                 result.add(newDisplay);
             }
@@ -339,12 +339,12 @@
         }
 
         @Nullable
-        public ActivityDisplay createDisplay() {
+        public DisplayContent createDisplay() {
             return createDisplays(1).stream().findFirst().orElse(null);
         }
 
         @NonNull
-        List<ActivityDisplay> createDisplays(int count) {
+        List<DisplayContent> createDisplays(int count) {
             if (mSimulateDisplay) {
                 return simulateDisplay();
             } else {
@@ -371,9 +371,9 @@
          * <pre>
          * <code>mDensityDpi</code> provide custom density for the display.
          * </pre>
-         * @return {@link ActivityDisplay} of newly created display.
+         * @return {@link DisplayContent} of newly created display.
          */
-        private List<ActivityDisplay> simulateDisplay() {
+        private List<DisplayContent> simulateDisplay() {
             // Create virtual display with custom density dpi and specified size.
             mOverlayDisplayDeviceSession.set(mSimulationDisplaySize + "/" + mDensityDpi);
             if (mShowSystemDecorations) {
@@ -399,10 +399,10 @@
          *     creation.
          * </pre>
          * @param displayCount number of displays to be created.
-         * @return A list of {@link ActivityDisplay} that represent newly created displays.
+         * @return A list of {@link DisplayContent} that represent newly created displays.
          * @throws Exception
          */
-        private List<ActivityDisplay> createVirtualDisplays(int displayCount) {
+        private List<DisplayContent> createVirtualDisplays(int displayCount) {
             // Start an activity that is able to create virtual displays.
             if (mLaunchInSplitScreen) {
                 getLaunchActivityBuilder()
@@ -417,7 +417,7 @@
             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
             mAmWmState.assertFocusedActivity("Focus must be on virtual display host activity",
                     VIRTUAL_DISPLAY_ACTIVITY);
-            final List<ActivityDisplay> originalDS = getDisplaysStates();
+            final List<DisplayContent> originalDS = getDisplaysStates();
 
             // Create virtual display with custom density dpi.
             final StringBuilder createVirtualDisplayCommand = new StringBuilder(
@@ -466,13 +466,13 @@
         private final ActivitySessionClient mActivitySessionClient = createActivitySessionClient();
 
         ActivitySession launchActivityOnDisplay(ComponentName activityName,
-                ActivityDisplay display) {
+                DisplayContent display) {
             return launchActivityOnDisplay(activityName, display, null /* extrasConsumer */,
                     true /* withShellPermission */, true /* waitForLaunch */);
         }
 
         ActivitySession launchActivityOnDisplay(ComponentName activityName,
-                ActivityDisplay display, Consumer<Bundle> extrasConsumer,
+                DisplayContent display, Consumer<Bundle> extrasConsumer,
                 boolean withShellPermission, boolean waitForLaunch) {
             return launchActivity(builder -> builder
                     // VirtualDisplayActivity is in different package. If the display is not public,
@@ -502,7 +502,7 @@
     /** Helper class to save, set, and restore overlay_display_devices preference. */
     private class OverlayDisplayDevicesSession extends SettingsSession<String> {
         /** The displays which are created by this session. */
-        private final List<ActivityDisplay> mDisplays = new ArrayList<>();
+        private final List<DisplayContent> mDisplays = new ArrayList<>();
         /** The configured displays that need to be restored when this session is closed. */
         private final List<OverlayDisplayState> mDisplayStates = new ArrayList<>();
         private final WindowManager mWm;
@@ -516,13 +516,13 @@
             mWm = context.getSystemService(WindowManager.class);
         }
 
-        List<ActivityDisplay> getCreatedDisplays() {
+        List<DisplayContent> getCreatedDisplays() {
             return new ArrayList<>(mDisplays);
         }
 
         @Override
         public void set(String value) {
-            final List<ActivityDisplay> originalDisplays = getDisplaysStates();
+            final List<DisplayContent> originalDisplays = getDisplaysStates();
             super.set(value);
             final int newDisplayCount = 1 + (int) value.chars().filter(ch -> ch == ';').count();
             mDisplays.addAll(assertAndGetNewDisplays(newDisplayCount, originalDisplays));
@@ -530,7 +530,7 @@
 
         void configureDisplays(boolean requestShowSysDecors, boolean requestShowIme) {
             SystemUtil.runWithShellPermissionIdentity(() -> {
-                for (ActivityDisplay display : mDisplays) {
+                for (DisplayContent display : mDisplays) {
                     final boolean showSystemDecors = mWm.shouldShowSystemDecors(display.mId);
                     final boolean showIme = mWm.shouldShowIme(display.mId);
                     mDisplayStates.add(new OverlayDisplayState(
@@ -590,7 +590,7 @@
     }
 
     /** Wait for provided number of displays and report their configurations. */
-    List<ActivityDisplay> getDisplayStateAfterChange(int expectedDisplayCount) {
+    List<DisplayContent> getDisplayStateAfterChange(int expectedDisplayCount) {
         return Condition.waitForResult("the correct number of displays=" + expectedDisplayCount,
                 condition -> condition
                         .setReturnLastResult(true)
@@ -599,11 +599,11 @@
                                 displays -> areDisplaysValid(displays, expectedDisplayCount)));
     }
 
-    private boolean areDisplaysValid(List<ActivityDisplay> displays, int expectedDisplayCount) {
+    private boolean areDisplaysValid(List<DisplayContent> displays, int expectedDisplayCount) {
         if (displays.size() != expectedDisplayCount) {
             return false;
         }
-        for (ActivityDisplay display : displays) {
+        for (DisplayContent display : displays) {
             if (display.mOverrideConfiguration.densityDpi == 0) {
                 return false;
             }
@@ -618,12 +618,12 @@
      * @param originalDisplays display states before creation of new display(s).
      * @return list of new displays, empty list if no new display is created.
      */
-    private List<ActivityDisplay> assertAndGetNewDisplays(int newDisplayCount,
-            List<ActivityDisplay> originalDisplays) {
+    private List<DisplayContent> assertAndGetNewDisplays(int newDisplayCount,
+            List<DisplayContent> originalDisplays) {
         final int originalDisplayCount = originalDisplays.size();
 
         // Wait for the display(s) to be created and get configurations.
-        final List<ActivityDisplay> ds = getDisplayStateAfterChange(
+        final List<DisplayContent> ds = getDisplayStateAfterChange(
                 originalDisplayCount + newDisplayCount);
         if (newDisplayCount != -1) {
             assertEquals("New virtual display(s) must be created",
@@ -635,7 +635,7 @@
         }
 
         // Find the newly added display(s).
-        final List<ActivityDisplay> newDisplays = findNewDisplayStates(originalDisplays, ds);
+        final List<DisplayContent> newDisplays = findNewDisplayStates(originalDisplays, ds);
         assertThat("New virtual display must be created", newDisplays, hasSize(newDisplayCount));
 
         return newDisplays;
@@ -710,8 +710,8 @@
         /**
          * Creates a private virtual display with insecure keyguard flags set.
          */
-        ActivityDisplay createVirtualDisplay() {
-            final List<ActivityDisplay> originalDS = getDisplaysStates();
+        DisplayContent createVirtualDisplay() {
+            final List<DisplayContent> originalDS = getDisplaysStates();
             final int originalDisplayCount = originalDS.size();
 
             mExternalDisplayHelper = new VirtualDisplayHelper();
@@ -722,12 +722,12 @@
                     .createAndWaitForDisplay();
 
             // Wait for the virtual display to be created and get configurations.
-            final List<ActivityDisplay> ds = getDisplayStateAfterChange(originalDisplayCount + 1);
+            final List<DisplayContent> ds = getDisplayStateAfterChange(originalDisplayCount + 1);
             assertEquals("New virtual display must be created", originalDisplayCount + 1,
                     ds.size());
 
             // Find the newly added display.
-            final ActivityDisplay newDisplay = findNewDisplayStates(originalDS, ds).get(0);
+            final DisplayContent newDisplay = findNewDisplayStates(originalDS, ds).get(0);
             mDisplayId = newDisplay.mId;
             return newDisplay;
         }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
index a410ee1..56f7e0b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
@@ -269,7 +269,7 @@
 
         // Move to split-screen primary
         final int taskId = mAmWmState.getAmState().getTaskByActivity(LAUNCHING_ACTIVITY).mTaskId;
-        moveTaskToPrimarySplitScreen(taskId, true /* showRecents */);
+        moveTaskToPrimarySplitScreen(taskId, true /* showSideActivity */);
 
         // Launch target to side
         final LaunchActivityBuilder targetActivityLauncher = getLaunchActivityBuilder()
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java
index 9573cfa..26026e2 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java
@@ -31,7 +31,7 @@
 import android.content.ComponentName;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
-import android.server.wm.ActivityManagerState.ActivityDisplay;
+import android.server.wm.ActivityManagerState.DisplayContent;
 import android.server.wm.settings.SettingsSession;
 
 import com.android.cts.verifier.vr.MockVrListenerService;
@@ -140,8 +140,8 @@
                 getActivityName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
 
         // Check if the launch activity is in Vr virtual display id.
-        final List<ActivityDisplay> reportedDisplays = getDisplaysStates();
-        final ActivityDisplay vrDisplay = getDisplayState(reportedDisplays,
+        final List<DisplayContent> reportedDisplays = getDisplaysStates();
+        final DisplayContent vrDisplay = getDisplayState(reportedDisplays,
                 VR_VIRTUAL_DISPLAY_WIDTH, VR_VIRTUAL_DISPLAY_HEIGHT, VR_VIRTUAL_DISPLAY_DPI);
         assertNotNull("Vr mode should have a virtual display", vrDisplay);
 
@@ -190,8 +190,8 @@
                 getActivityName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
 
         // Check if the launch activity is in Vr virtual display id.
-        final List<ActivityDisplay> reportedDisplays = getDisplaysStates();
-        final ActivityDisplay vrDisplay = getDisplayState(reportedDisplays,
+        final List<DisplayContent> reportedDisplays = getDisplaysStates();
+        final DisplayContent vrDisplay = getDisplayState(reportedDisplays,
                 VR_VIRTUAL_DISPLAY_WIDTH, VR_VIRTUAL_DISPLAY_HEIGHT, VR_VIRTUAL_DISPLAY_DPI);
         assertNotNull("Vr mode should have a virtual display", vrDisplay);
 
@@ -240,8 +240,8 @@
                     focusedStack.mResumedActivity);
 
             // Check if the launch activity is in Vr virtual display id.
-            final List<ActivityDisplay> reportedDisplays = getDisplaysStates();
-            final ActivityDisplay vrDisplay = getDisplayState(reportedDisplays,
+            final List<DisplayContent> reportedDisplays = getDisplaysStates();
+            final DisplayContent vrDisplay = getDisplayState(reportedDisplays,
                     VR_VIRTUAL_DISPLAY_WIDTH, VR_VIRTUAL_DISPLAY_HEIGHT,
                     VR_VIRTUAL_DISPLAY_DPI);
             assertNotNull("Vr mode should have a virtual display", vrDisplay);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
index 55e3b63..2cf5469 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
@@ -128,7 +128,7 @@
 
         assumeTrue(supportsMultiDisplay());
         try (VirtualDisplaySession displaySession = new VirtualDisplaySession()) {
-            final ActivityManagerState.ActivityDisplay display = displaySession
+            final ActivityManagerState.DisplayContent display = displaySession
                     .setPublicDisplay(true).setSimulateDisplay(true).createDisplay();
             final int secondaryDisplayId = display.mId;
             final SecondaryActivity secondaryActivity =
@@ -182,7 +182,7 @@
                 DEFAULT_DISPLAY);
 
         try (VirtualDisplaySession displaySession = new VirtualDisplaySession()) {
-            final ActivityManagerState.ActivityDisplay display = displaySession
+            final ActivityManagerState.DisplayContent display = displaySession
                     .setPublicDisplay(true).setSimulateDisplay(true).createDisplay();
             final int secondaryDisplayId = display.mId;
             final SecondaryActivity secondaryActivity =
@@ -228,7 +228,7 @@
 
         assumeTrue(supportsMultiDisplay());
         try (VirtualDisplaySession displaySession = new VirtualDisplaySession()) {
-            final ActivityManagerState.ActivityDisplay display = displaySession
+            final ActivityManagerState.DisplayContent display = displaySession
                     .setPublicDisplay(true).setSimulateDisplay(true).createDisplay();
             final int secondaryDisplayId = display.mId;
             final SecondaryActivity secondaryActivity =
@@ -260,7 +260,7 @@
 
         final SecondaryActivity secondaryActivity;
         try (VirtualDisplaySession displaySession = new VirtualDisplaySession()) {
-            final ActivityManagerState.ActivityDisplay display = displaySession
+            final ActivityManagerState.DisplayContent display = displaySession
                     .setPublicDisplay(true).createDisplay();
             final int secondaryDisplayId = display.mId;
             // For launching activity on untrusted display, by default the activity will not get
@@ -289,7 +289,7 @@
         PrimaryActivity primaryActivity = startActivity(PrimaryActivity.class, DEFAULT_DISPLAY);
 
         try (VirtualDisplaySession displaySession = new VirtualDisplaySession()) {
-            final ActivityManagerState.ActivityDisplay display = displaySession
+            final ActivityManagerState.DisplayContent display = displaySession
                     .setPublicDisplay(true).setSimulateDisplay(true).createDisplay();
             final int secondaryDisplayId = display.mId;
             SecondaryActivity secondaryActivity = startActivity(SecondaryActivity.class,
@@ -314,7 +314,7 @@
         PrimaryActivity primaryActivity = startActivity(PrimaryActivity.class, DEFAULT_DISPLAY);
 
         try (VirtualDisplaySession displaySession = new VirtualDisplaySession()) {
-            final ActivityManagerState.ActivityDisplay display = displaySession
+            final ActivityManagerState.DisplayContent display = displaySession
                     .setPublicDisplay(true).setSimulateDisplay(true).createDisplay();
             final int secondaryDisplayId = display.mId;
             SecondaryActivity secondaryActivity = startActivity(SecondaryActivity.class,
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java
index 2c3985e..04b8966 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java
@@ -746,7 +746,7 @@
 
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             // Create new simulated display
-            final ActivityManagerState.ActivityDisplay newDisplay
+            final ActivityManagerState.DisplayContent newDisplay
                     = virtualDisplaySession.setSimulateDisplay(true).createDisplay();
 
             // Launch another activity on new secondary display.
@@ -795,7 +795,7 @@
                 DEFAULT_DISPLAY, "Activity launched on default display must be focused");
 
         // Create new simulated display
-        final ActivityManagerState.ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final ActivityManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -845,7 +845,7 @@
         assumeTrue(supportsMultiDisplay());
 
         // Create new simulated display.
-        final ActivityManagerState.ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final ActivityManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -914,7 +914,7 @@
         assumeTrue(supportsMultiDisplay());
 
         // Create new simulated display.
-        final ActivityManagerState.ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final ActivityManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -989,7 +989,7 @@
                 DEFAULT_DISPLAY, "Activity launched on default display must be focused");
 
         // Create new simulated display.
-        final ActivityManagerState.ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final ActivityManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
@@ -1034,7 +1034,7 @@
                 DEFAULT_DISPLAY, "Activity launched on default display must be focused");
 
         // Create new simulated display.
-        final ActivityManagerState.ActivityDisplay newDisplay = createManagedVirtualDisplaySession()
+        final ActivityManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
 
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerState.java
index 9449d71..dbdcc74 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerState.java
@@ -68,7 +68,7 @@
     private static final String DUMPSYS_ACTIVITY_ACTIVITIES = "dumpsys activity --proto activities";
 
     // Displays in z-order with the top most at the front of the list, starting with primary.
-    private final List<ActivityDisplay> mDisplays = new ArrayList<>();
+    private final List<DisplayContent> mDisplays = new ArrayList<>();
     // Stacks in z-order with the top most at the front of the list, starting with primary display.
     private final List<ActivityStack> mStacks = new ArrayList<>();
     private KeyguardControllerState mKeyguardControllerState;
@@ -160,7 +160,7 @@
                 .activityStackSupervisor;
         for (int i = 0; i < state.displays.length; i++) {
             ActivityDisplayProto activityDisplay = state.displays[i];
-            mDisplays.add(new ActivityDisplay(activityDisplay, this));
+            mDisplays.add(new DisplayContent(activityDisplay, this));
         }
         mKeyguardControllerState = new KeyguardControllerState(state.keyguardController);
         mTopFocusedStackId = state.focusedStackId;
@@ -196,8 +196,8 @@
         return mIsHomeRecentsComponent;
     }
 
-    ActivityDisplay getDisplay(int displayId) {
-        for (ActivityDisplay display : mDisplays) {
+    DisplayContent getDisplay(int displayId) {
+        for (DisplayContent display : mDisplays) {
             if (display.mId == displayId) {
                 return display;
             }
@@ -339,7 +339,7 @@
 
     /** Get the stack position on its display. */
     int getStackIndexByActivityType(int activityType) {
-        for (ActivityDisplay display : mDisplays) {
+        for (DisplayContent display : mDisplays) {
             for (int i = 0; i < display.mStacks.size(); i++) {
                 if (activityType == display.mStacks.get(i).getActivityType()) {
                     return i;
@@ -353,7 +353,7 @@
     int getStackIndexByActivity(ComponentName activityName) {
         final String fullName = getActivityName(activityName);
 
-        for (ActivityDisplay display : mDisplays) {
+        for (DisplayContent display : mDisplays) {
             for (int i = display.mStacks.size() - 1; i >= 0; --i) {
                 final ActivityStack stack = display.mStacks.get(i);
                 for (ActivityTask task : stack.mTasks) {
@@ -377,7 +377,7 @@
         return getStackById(task.mStackId).mDisplayId;
     }
 
-    List<ActivityDisplay> getDisplays() {
+    List<DisplayContent> getDisplays() {
         return new ArrayList<>(mDisplays);
     }
 
@@ -641,7 +641,7 @@
         return mPendingActivities.contains(getActivityName(activityName));
     }
 
-    public static class ActivityDisplay extends ActivityContainer {
+    public static class DisplayContent extends ActivityContainer {
 
         public int mId;
         ArrayList<ActivityStack> mStacks = new ArrayList<>();
@@ -649,7 +649,7 @@
         String mResumedActivity;
         boolean mSingleTaskInstance;
 
-        ActivityDisplay(ActivityDisplayProto proto, ActivityManagerState amState) {
+        DisplayContent(ActivityDisplayProto proto, ActivityManagerState amState) {
             super(proto.display.windowContainer.configurationContainer);
             mId = proto.id;
             mFocusedStackId = proto.focusedStackId;
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 1318de2..d8eab7e 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -738,7 +738,7 @@
     }
 
     public void moveTaskToPrimarySplitScreen(int taskId) {
-        moveTaskToPrimarySplitScreen(taskId, false /* showRecents */);
+        moveTaskToPrimarySplitScreen(taskId, false /* showSideActivity */);
     }
 
     /**
@@ -763,7 +763,8 @@
                     // Launch Placeholder Side Activity
                     final ComponentName sideActivityName =
                             new ComponentName(mContext, SideActivity.class);
-                    launchActivityNoWait(sideActivityName);
+                    mContext.startActivity(new Intent().setComponent(sideActivityName)
+                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                     mAmWmState.waitForActivityState(sideActivityName, STATE_RESUMED);
                 }
 
@@ -2189,7 +2190,10 @@
         }
     }
 
-    // Activity used in place of recents when home is the recents component.
+    /**
+     * Activity used in place of recents when home is the recents component. It should only be used
+     * by {@link #moveTaskToPrimarySplitScreen}.
+     */
     public static class SideActivity extends Activity {
     }
 }
diff --git a/tests/location/common/src/android/location/cts/common/BroadcastCapture.java b/tests/location/common/src/android/location/cts/common/BroadcastCapture.java
new file mode 100644
index 0000000..f2ea3ae
--- /dev/null
+++ b/tests/location/common/src/android/location/cts/common/BroadcastCapture.java
@@ -0,0 +1,64 @@
+/*
+ * 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.location.cts.common;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Looper;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class BroadcastCapture extends BroadcastReceiver implements AutoCloseable {
+
+    protected final Context mContext;
+    private final LinkedBlockingQueue<Intent> mIntents;
+
+    public BroadcastCapture(Context context, String action) {
+        this(context);
+        register(action);
+    }
+
+    protected BroadcastCapture(Context context) {
+        mContext = context;
+        mIntents = new LinkedBlockingQueue<>();
+    }
+
+    protected void register(String action) {
+        mContext.registerReceiver(this, new IntentFilter(action));
+    }
+
+    public Intent getNextIntent(long timeoutMs) throws InterruptedException {
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            throw new AssertionError("getNextLocation() called from main thread");
+        }
+
+        return mIntents.poll(timeoutMs, TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public void close() {
+        mContext.unregisterReceiver(this);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mIntents.add(intent);
+    }
+}
\ No newline at end of file
diff --git a/tests/location/common/src/android/location/cts/common/LocationPendingIntentCapture.java b/tests/location/common/src/android/location/cts/common/LocationPendingIntentCapture.java
index 22432dc..5afb7b3 100644
--- a/tests/location/common/src/android/location/cts/common/LocationPendingIntentCapture.java
+++ b/tests/location/common/src/android/location/cts/common/LocationPendingIntentCapture.java
@@ -32,19 +32,19 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class LocationPendingIntentCapture extends BroadcastReceiver implements AutoCloseable {
+public class LocationPendingIntentCapture extends BroadcastCapture {
 
     private static final String ACTION = "android.location.cts.LOCATION_BROADCAST";
     private static final AtomicInteger sRequestCode = new AtomicInteger(0);
 
-    private final Context mContext;
     private final LocationManager mLocationManager;
     private final PendingIntent mPendingIntent;
     private final LinkedBlockingQueue<Location> mLocations;
     private final LinkedBlockingQueue<Boolean> mProviderChanges;
 
     public LocationPendingIntentCapture(Context context) {
-        mContext = context;
+        super(context);
+
         mLocationManager = context.getSystemService(LocationManager.class);
         mPendingIntent = PendingIntent.getBroadcast(context, sRequestCode.getAndIncrement(),
                 new Intent(ACTION).setPackage(context.getPackageName()),
@@ -52,7 +52,7 @@
         mLocations = new LinkedBlockingQueue<>();
         mProviderChanges = new LinkedBlockingQueue<>();
 
-        context.registerReceiver(this, new IntentFilter(ACTION));
+        register(ACTION);
     }
 
     public PendingIntent getPendingIntent() {
@@ -77,13 +77,14 @@
 
     @Override
     public void close() {
+        super.close();
         mLocationManager.removeUpdates(mPendingIntent);
-        mContext.unregisterReceiver(this);
         mPendingIntent.cancel();
     }
 
     @Override
     public void onReceive(Context context, Intent intent) {
+        super.onReceive(context, intent);
         if (intent.hasExtra(KEY_PROVIDER_ENABLED)) {
             mProviderChanges.add(intent.getBooleanExtra(KEY_PROVIDER_ENABLED, false));
         } else if (intent.hasExtra(KEY_LOCATION_CHANGED)) {
diff --git a/tests/location/common/src/android/location/cts/common/ProximityPendingIntentCapture.java b/tests/location/common/src/android/location/cts/common/ProximityPendingIntentCapture.java
index c8f1c06..75e4e39 100644
--- a/tests/location/common/src/android/location/cts/common/ProximityPendingIntentCapture.java
+++ b/tests/location/common/src/android/location/cts/common/ProximityPendingIntentCapture.java
@@ -14,25 +14,25 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class ProximityPendingIntentCapture extends BroadcastReceiver implements AutoCloseable {
+public class ProximityPendingIntentCapture extends BroadcastCapture {
 
     private static final String ACTION = "android.location.cts.LOCATION_BROADCAST";
     private static final AtomicInteger sRequestCode = new AtomicInteger(0);
 
-    private final Context mContext;
     private final LocationManager mLocationManager;
     private final PendingIntent mPendingIntent;
     private final LinkedBlockingQueue<Boolean> mProximityChanges;
 
     public ProximityPendingIntentCapture(Context context) {
-        mContext = context;
+        super(context);
+
         mLocationManager = context.getSystemService(LocationManager.class);
         mPendingIntent = PendingIntent.getBroadcast(context, sRequestCode.getAndIncrement(),
                 new Intent(ACTION).setPackage(context.getPackageName()),
                 PendingIntent.FLAG_CANCEL_CURRENT);
         mProximityChanges = new LinkedBlockingQueue<>();
 
-        context.registerReceiver(this, new IntentFilter(ACTION));
+        register(ACTION);
     }
 
     public PendingIntent getPendingIntent() {
@@ -49,13 +49,14 @@
 
     @Override
     public void close() {
+        super.close();
         mLocationManager.removeProximityAlert(mPendingIntent);
-        mContext.unregisterReceiver(this);
         mPendingIntent.cancel();
     }
 
     @Override
     public void onReceive(Context context, Intent intent) {
+        super.onReceive(context, intent);
         if (intent.hasExtra(KEY_PROXIMITY_ENTERING)) {
             mProximityChanges.add(intent.getBooleanExtra(KEY_PROXIMITY_ENTERING, false));
         }
diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
index c57107d..c147cfd 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
@@ -16,22 +16,21 @@
 
 package android.location.cts.fine;
 
+import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
+import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
 import static android.location.LocationManager.FUSED_PROVIDER;
 import static android.location.LocationManager.GPS_PROVIDER;
 import static android.location.LocationManager.NETWORK_PROVIDER;
 import static android.location.LocationManager.PASSIVE_PROVIDER;
+import static android.location.LocationManager.PROVIDERS_CHANGED_ACTION;
 
+import static androidx.test.ext.truth.content.IntentSubject.assertThat;
 import static androidx.test.ext.truth.location.LocationSubject.assertThat;
 
 import static com.android.compatibility.common.util.LocationUtils.createLocation;
 
 import static com.google.common.truth.Truth.assertThat;
 
-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 static org.junit.Assert.fail;
 
 import android.app.PendingIntent;
@@ -50,6 +49,7 @@
 import android.location.LocationProvider;
 import android.location.LocationRequest;
 import android.location.OnNmeaMessageListener;
+import android.location.cts.common.BroadcastCapture;
 import android.location.cts.common.GetCurrentLocationCapture;
 import android.location.cts.common.LocationListenerCapture;
 import android.location.cts.common.LocationPendingIntentCapture;
@@ -74,6 +74,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
@@ -106,7 +107,7 @@
         mContext = ApplicationProvider.getApplicationContext();
         mManager = mContext.getSystemService(LocationManager.class);
 
-        assertNotNull(mManager);
+        assertThat(mManager).isNotNull();
 
         for (String provider : mManager.getAllProviders()) {
             mManager.removeTestProvider(provider);
@@ -137,7 +138,7 @@
 
     @Test
     public void testIsLocationEnabled() {
-        assertTrue(mManager.isLocationEnabled());
+        assertThat(mManager.isLocationEnabled()).isTrue();
     }
 
     @Test
@@ -150,13 +151,13 @@
 
     @Test
     public void testIsProviderEnabled() {
-        assertTrue(mManager.isProviderEnabled(TEST_PROVIDER));
+        assertThat(mManager.isProviderEnabled(TEST_PROVIDER)).isTrue();
 
         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
-        assertFalse(mManager.isProviderEnabled(TEST_PROVIDER));
+        assertThat(mManager.isProviderEnabled(TEST_PROVIDER)).isFalse();
 
         mManager.setTestProviderEnabled(TEST_PROVIDER, true);
-        assertTrue(mManager.isProviderEnabled(TEST_PROVIDER));
+        assertThat(mManager.isProviderEnabled(TEST_PROVIDER)).isTrue();
 
         try {
             mManager.isProviderEnabled(null);
@@ -178,7 +179,7 @@
         assertThat(mManager.getLastKnownLocation(TEST_PROVIDER)).isEqualTo(loc2);
 
         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
-        assertNull(mManager.getLastKnownLocation(TEST_PROVIDER));
+        assertThat(mManager.getLastKnownLocation(TEST_PROVIDER)).isNull();
 
         try {
             mManager.getLastKnownLocation(null);
@@ -226,10 +227,10 @@
 
         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
-                    Runnable::run, capture);
+                    Executors.newSingleThreadExecutor(), capture);
             capture.getCancellationSignal().cancel();
             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
-            assertFalse(capture.hasLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.hasLocation(FAILURE_TIMEOUT_MS)).isFalse();
         }
     }
 
@@ -238,15 +239,15 @@
         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
-                    Runnable::run, capture);
-            assertNull(capture.getLocation(FAILURE_TIMEOUT_MS));
+                    Executors.newSingleThreadExecutor(), capture);
+            assertThat(capture.getLocation(FAILURE_TIMEOUT_MS)).isNull();
         }
 
         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
-                    Runnable::run, capture);
+                    Executors.newSingleThreadExecutor(), capture);
             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
-            assertNull(capture.getLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getLocation(FAILURE_TIMEOUT_MS)).isNull();
         }
     }
 
@@ -271,11 +272,11 @@
             mManager.removeUpdates(capture);
 
             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
-            assertNull(capture.getNextLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
-            assertNull(capture.getNextProviderChange(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
-            assertNull(capture.getNextProviderChange(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
         }
 
         try {
@@ -327,11 +328,11 @@
             mManager.removeUpdates(capture.getPendingIntent());
 
             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
-            assertNull(capture.getNextLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
-            assertNull(capture.getNextProviderChange(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
-            assertNull(capture.getNextProviderChange(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
         }
 
         try {
@@ -426,7 +427,7 @@
         Location loc2 = createLocation(FUSED_PROVIDER, mRandom);
 
         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
-            mManager.requestLocationUpdates(0, 0, criteria, Runnable::run, capture);
+            mManager.requestLocationUpdates(0, 0, criteria, Executors.newSingleThreadExecutor(), capture);
 
             mManager.setTestProviderLocation(FUSED_PROVIDER, loc1);
             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
@@ -440,11 +441,11 @@
             mManager.removeUpdates(capture);
 
             mManager.setTestProviderLocation(FUSED_PROVIDER, loc1);
-            assertNull(capture.getNextLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
             mManager.setTestProviderEnabled(FUSED_PROVIDER, false);
-            assertNull(capture.getNextProviderChange(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
             mManager.setTestProviderEnabled(FUSED_PROVIDER, true);
-            assertNull(capture.getNextProviderChange(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
         }
 
 
@@ -463,7 +464,7 @@
         }
 
         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
-            mManager.requestLocationUpdates(0, 0, null, Runnable::run, capture);
+            mManager.requestLocationUpdates(0, 0, null, Executors.newSingleThreadExecutor(), capture);
             fail("Should throw IllegalArgumentException if criteria is null!");
         } catch (IllegalArgumentException e) {
             // expected
@@ -476,8 +477,8 @@
         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
 
         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
-            mManager.requestLocationUpdates(TEST_PROVIDER, 1000, 1000, Runnable::run, capture);
-            mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, Runnable::run, capture);
+            mManager.requestLocationUpdates(TEST_PROVIDER, 1000, 1000, (runnable) -> {}, capture);
+            mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, Executors.newSingleThreadExecutor(), capture);
 
             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
@@ -496,12 +497,12 @@
         request.setNumUpdates(1);
 
         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
-            mManager.requestLocationUpdates(request, Runnable::run, capture);
+            mManager.requestLocationUpdates(request, Executors.newSingleThreadExecutor(), capture);
 
             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
-            assertNull(capture.getNextLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
         }
     }
 
@@ -514,12 +515,12 @@
                 0, false);
 
         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
-            mManager.requestLocationUpdates(request, Runnable::run, capture);
+            mManager.requestLocationUpdates(request, Executors.newSingleThreadExecutor(), capture);
 
             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
-            assertNull(capture.getNextLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
         }
     }
 
@@ -532,12 +533,12 @@
                 200000, false);
 
         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
-            mManager.requestLocationUpdates(request, Runnable::run, capture);
+            mManager.requestLocationUpdates(request, Executors.newSingleThreadExecutor(), capture);
 
             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
-            assertNull(capture.getNextLocation(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
         }
     }
 
@@ -546,7 +547,7 @@
     public void testRequestGpsUpdates_B9758659() throws Exception {
         // test for b/9758659, where the gps provider may reuse network provider positions creating
         // an unnatural feedback loop
-        assertTrue(mManager.isProviderEnabled(GPS_PROVIDER));
+        assertThat(mManager.isProviderEnabled(GPS_PROVIDER)).isTrue();
 
         Location networkLocation = createLocation(NETWORK_PROVIDER, mRandom);
 
@@ -568,7 +569,7 @@
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(GPS_PROVIDER, 0, 0, false);
         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
-            mManager.requestLocationUpdates(request, Runnable::run, capture);
+            mManager.requestLocationUpdates(request, Executors.newSingleThreadExecutor(), capture);
 
             Location location = capture.getNextLocation(TIMEOUT_MS);
             if (location != null) {
@@ -578,36 +579,91 @@
     }
 
     @Test
+    public void testListenProviderEnable_Listener() throws Exception {
+        try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
+            mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
+                    Executors.newSingleThreadExecutor(), capture);
+
+            mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+            assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(false);
+            mManager.setTestProviderEnabled(TEST_PROVIDER, true);
+            assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(true);
+
+            mManager.removeUpdates(capture);
+
+            mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
+        }
+    }
+
+    @Test
+    public void testListenProviderEnable_PendingIntent() throws Exception {
+        try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
+            mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, capture.getPendingIntent());
+
+            mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+            assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(false);
+            mManager.setTestProviderEnabled(TEST_PROVIDER, true);
+            assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(true);
+
+            mManager.removeUpdates(capture.getPendingIntent());
+
+            mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+            assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
+        }
+    }
+
+    @Test
+    public void testListenProviderEnable_Broadcast() throws Exception {
+        try (BroadcastCapture capture = new BroadcastCapture(mContext, PROVIDERS_CHANGED_ACTION)) {
+            mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+            Intent broadcast = capture.getNextIntent(TIMEOUT_MS);
+            assertThat(broadcast).isNotNull();
+            assertThat(broadcast).hasAction(PROVIDERS_CHANGED_ACTION);
+            assertThat(broadcast).extras().string(EXTRA_PROVIDER_NAME).isEqualTo(TEST_PROVIDER);
+            assertThat(broadcast).extras().bool(EXTRA_PROVIDER_ENABLED).isFalse();
+
+            mManager.setTestProviderEnabled(TEST_PROVIDER, true);
+            broadcast = capture.getNextIntent(TIMEOUT_MS);
+            assertThat(broadcast).isNotNull();
+            assertThat(broadcast).hasAction(PROVIDERS_CHANGED_ACTION);
+            assertThat(broadcast).extras().string(EXTRA_PROVIDER_NAME).isEqualTo(TEST_PROVIDER);
+            assertThat(broadcast).extras().bool(EXTRA_PROVIDER_ENABLED).isTrue();
+        }
+    }
+
+    @Test
     public void testGetAllProviders() {
         List<String> providers = mManager.getAllProviders();
         if (hasGpsFeature()) {
-            assertTrue(providers.contains(LocationManager.GPS_PROVIDER));
+            assertThat(providers.contains(LocationManager.GPS_PROVIDER)).isTrue();
         }
-        assertTrue(providers.contains(PASSIVE_PROVIDER));
-        assertTrue(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(PASSIVE_PROVIDER)).isTrue();
+        assertThat(providers.contains(TEST_PROVIDER)).isTrue();
+        assertThat(providers.size()).isEqualTo(new HashSet<>(providers).size());
 
         mManager.removeTestProvider(TEST_PROVIDER);
 
         providers = mManager.getAllProviders();
-        assertTrue(providers.contains(PASSIVE_PROVIDER));
-        assertFalse(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(PASSIVE_PROVIDER)).isTrue();
+        assertThat(providers.contains(TEST_PROVIDER)).isFalse();
     }
 
     @Test
     public void testGetProviders() throws Exception {
         List<String> providers = mManager.getProviders(false);
-        assertTrue(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isTrue();
 
         providers = mManager.getProviders(true);
-        assertTrue(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isTrue();
 
         setTestProviderEnabled(TEST_PROVIDER, false);
 
         providers = mManager.getProviders(false);
-        assertTrue(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isTrue();
 
         providers = mManager.getProviders(true);
-        assertFalse(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isFalse();
     }
 
     @Test
@@ -615,18 +671,18 @@
         Criteria criteria = new Criteria();
 
         List<String> providers = mManager.getProviders(criteria, false);
-        assertTrue(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isTrue();
 
         providers = mManager.getProviders(criteria, true);
-        assertTrue(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isTrue();
 
         criteria.setPowerRequirement(Criteria.POWER_LOW);
 
         providers = mManager.getProviders(criteria, false);
-        assertFalse(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isFalse();
 
         providers = mManager.getProviders(criteria, true);
-        assertFalse(providers.contains(TEST_PROVIDER));
+        assertThat(providers.contains(TEST_PROVIDER)).isFalse();
     }
 
     @Test
@@ -661,21 +717,21 @@
         assertThat(mManager.getBestProvider(criteria, false)).isEqualTo(TEST_PROVIDER);
 
         setTestProviderEnabled(TEST_PROVIDER, false);
-        assertNotEquals(TEST_PROVIDER, mManager.getBestProvider(criteria, true));
+        assertThat(mManager.getBestProvider(criteria, true)).isNotEqualTo(TEST_PROVIDER);
     }
 
     @Test
     public void testGetProvider() {
         LocationProvider provider = mManager.getProvider(TEST_PROVIDER);
-        assertNotNull(provider);
+        assertThat(provider).isNotNull();
         assertThat(provider.getName()).isEqualTo(TEST_PROVIDER);
 
         provider = mManager.getProvider(LocationManager.GPS_PROVIDER);
         if (hasGpsFeature()) {
-            assertNotNull(provider);
+            assertThat(provider).isNotNull();
             assertThat(provider.getName()).isEqualTo(LocationManager.GPS_PROVIDER);
         } else {
-            assertNull(provider);
+            assertThat(provider).isNull();
         }
 
         try {
@@ -691,7 +747,7 @@
     public void testSendExtraCommand() {
         for (String provider : mManager.getAllProviders()) {
             boolean res = mManager.sendExtraCommand(provider, "dontCrash", null);
-            assertTrue(res);
+            assertThat(res).isTrue();
 
             try {
                 mManager.sendExtraCommand(provider, null, null);
@@ -763,25 +819,62 @@
     }
 
     @Test
+    public void testSetTestProviderEnabled() {
+        for (String provider : mManager.getAllProviders()) {
+            if (TEST_PROVIDER.equals(provider)) {
+                mManager.setTestProviderEnabled(provider, false);
+                assertThat(mManager.isProviderEnabled(provider)).isFalse();
+                mManager.setTestProviderEnabled(provider, true);
+                assertThat(mManager.isProviderEnabled(provider)).isTrue();
+            } else {
+                try {
+                    mManager.setTestProviderEnabled(provider, false);
+                    fail("Should throw IllegalArgumentException since " + provider
+                            + " is not a test provider!");
+                } catch (IllegalArgumentException e) {
+                    // expected
+                }
+            }
+        }
+
+        mManager.removeTestProvider(TEST_PROVIDER);
+        try {
+            mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+            fail("Should throw IllegalArgumentException since " + TEST_PROVIDER
+                    + " is not a test provider!");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            mManager.setTestProviderEnabled(null, false);
+            fail("Should throw IllegalArgumentException since provider is null!");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void testSetTestProviderLocation() throws Exception {
         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
 
         for (String provider : mManager.getAllProviders()) {
             if (TEST_PROVIDER.equals(provider)) {
-                try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
-                    mManager.getCurrentLocation(provider, capture.getCancellationSignal(),
-                            Runnable::run, capture);
+                try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
+                    mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
+                            Executors.newSingleThreadExecutor(), capture);
                     mManager.setTestProviderLocation(provider, loc1);
 
-                    Location received = capture.getLocation(TIMEOUT_MS);
+                    Location received = capture.getNextLocation(TIMEOUT_MS);
                     assertThat(received).isEqualTo(loc1);
-                    assertTrue(received.isFromMockProvider());
+                    assertThat(received.isFromMockProvider()).isTrue();
                     assertThat(mManager.getLastKnownLocation(provider)).isEqualTo(loc1);
 
                     setTestProviderEnabled(provider, false);
                     mManager.setTestProviderLocation(provider, loc2);
-                    assertNull(mManager.getLastKnownLocation(provider));
+                    assertThat(mManager.getLastKnownLocation(provider)).isNull();
+                    assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
                 }
             } else {
                 try {
@@ -827,8 +920,8 @@
         if (providers.size() <= 2) {
             // can't perform the test without any real providers, and no need to do so since there
             // are no providers a malicious app could fool
-            assertTrue(providers.contains(TEST_PROVIDER));
-            assertTrue(providers.contains(PASSIVE_PROVIDER));
+            assertThat(providers.contains(TEST_PROVIDER)).isTrue();
+            assertThat(providers.contains(PASSIVE_PROVIDER)).isTrue();
             return;
         }
 
@@ -840,12 +933,12 @@
 
         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
-                    Runnable::run, capture);
+                    Executors.newSingleThreadExecutor(), capture);
             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
 
             Location received = capture.getLocation(TIMEOUT_MS);
             assertThat(received).isEqualTo(loc);
-            assertTrue(received.isFromMockProvider());
+            assertThat(received.isFromMockProvider()).isTrue();
 
             Location realProvideLocation = mManager.getLastKnownLocation(realProvider);
             if (realProvideLocation != null) {
@@ -987,7 +1080,7 @@
             Thread.sleep(500);
 
             mManager.setTestProviderLocation(FUSED_PROVIDER, createLocation(FUSED_PROVIDER, 0, 0, 10));
-            assertNull(capture.getNextProximityChange(FAILURE_TIMEOUT_MS));
+            assertThat(capture.getNextProximityChange(FAILURE_TIMEOUT_MS)).isNull();
         }
     }
 
@@ -1008,7 +1101,7 @@
         GnssStatus.Callback callback = new GnssStatus.Callback() {
         };
 
-        mManager.registerGnssStatusCallback(Runnable::run, callback);
+        mManager.registerGnssStatusCallback(Executors.newSingleThreadExecutor(), callback);
         mManager.unregisterGnssStatusCallback(callback);
     }
 
@@ -1017,7 +1110,7 @@
         OnNmeaMessageListener listener = (message, timestamp) -> {
         };
 
-        mManager.addNmeaListener(Runnable::run, listener);
+        mManager.addNmeaListener(Executors.newSingleThreadExecutor(), listener);
         mManager.removeNmeaListener(listener);
     }
 
@@ -1026,7 +1119,7 @@
         GnssMeasurementsEvent.Callback callback = new GnssMeasurementsEvent.Callback() {
         };
 
-        mManager.registerGnssMeasurementsCallback(Runnable::run, callback);
+        mManager.registerGnssMeasurementsCallback(Executors.newSingleThreadExecutor(), callback);
         mManager.unregisterGnssMeasurementsCallback(callback);
     }
 
@@ -1035,7 +1128,7 @@
         GnssNavigationMessage.Callback callback = new GnssNavigationMessage.Callback() {
         };
 
-        mManager.registerGnssNavigationMessageCallback(Runnable::run, callback);
+        mManager.registerGnssNavigationMessageCallback(Executors.newSingleThreadExecutor(), callback);
         mManager.unregisterGnssNavigationMessageCallback(callback);
     }
 
@@ -1060,7 +1153,7 @@
                 }
             };
             mContext.registerReceiver(receiver,
-                    new IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION));
+                    new IntentFilter(PROVIDERS_CHANGED_ACTION));
             mManager.setTestProviderEnabled(provider, enabled);
 
             // it's ok if this times out, as we don't notify for noop changes
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BMPString.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BMPString.java
index 417fa37..2d74aa6 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BMPString.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BMPString.java
@@ -23,6 +23,7 @@
 
 import java.nio.ByteBuffer;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  * A BMP string is a string from the Basic Multilingual Plane of Unicode, i.e.
@@ -76,7 +77,7 @@
   }
 
   private Iterable<BitStream> encodePerImpl(boolean aligned) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     int length = Character.codePointCount(value, 0, value.length());
     Preconditions.checkState(length >= minimumSize, "Value too short.");
     Preconditions.checkState(maximumSize == null || length <= maximumSize,
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BitString.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BitString.java
index dcf50d7..a5265ef 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BitString.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1BitString.java
@@ -24,6 +24,7 @@
 import java.nio.ByteBuffer;
 import java.util.BitSet;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  * Implements ASN.1 functionality.
@@ -65,13 +66,13 @@
   }
 
   @Override int getBerValueLength() {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     // the +1 is for the extra leading octet indicating the number of unused bits in last octet
     return (value.length() + 7) / 8 + 1;
   }
 
   @Override void encodeBerValue(ByteBuffer buf) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     Preconditions.checkState(
         maximumSize == null || value.length() <= maximumSize, "Too large %s",
         value.length());
@@ -98,7 +99,7 @@
   }
 
   private Iterable<BitStream> encodePerImpl(boolean aligned) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     Preconditions.checkState(
         maximumSize == null || value.length() <= maximumSize, "Too large %s",
         value.length());
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Enumerated.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Enumerated.java
index d39bb39..5e16c69 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Enumerated.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Enumerated.java
@@ -16,12 +16,12 @@
 
 package android.location.cts.asn1.base;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  */
@@ -85,7 +85,7 @@
   }
 
   private Asn1Integer asAsn1Integer() {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     Asn1Integer ai = new Asn1Integer();
     ai.setInteger(BigInteger.valueOf(value.getAssignedValue()));
     return ai;
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1GeneralString.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1GeneralString.java
index 29b874b..4f0159a 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1GeneralString.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1GeneralString.java
@@ -23,6 +23,7 @@
 
 import java.nio.ByteBuffer;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  * A general string is any ISO 646 related 8-bit encoding, presumably agreed on
@@ -75,7 +76,7 @@
   }
 
   private Iterable<BitStream> encodePerImpl(boolean aligned) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     Preconditions.checkState(value.length >= minimumSize, "Value too short.");
     Preconditions.checkState(maximumSize == null || value.length <= maximumSize,
                              "Value too long.");
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1IA5String.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1IA5String.java
index 0c2da9c..dff4822 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1IA5String.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1IA5String.java
@@ -31,6 +31,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  * Represents strings in 7-bit US ASCII (actually pages 1 and 6 of ISO
@@ -58,12 +59,12 @@
   }
 
   @Override int getBerValueLength() {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     return value.length();
   }
 
   @Override void encodeBerValue(ByteBuffer buf) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     buf.put(value.getBytes(StandardCharsets.US_ASCII));
   }
 
@@ -72,7 +73,7 @@
   }
 
   protected void setAlphabet(String alphabet) {
-    Preconditions.checkNotNull(alphabet);
+    Objects.requireNonNull(alphabet);
     Preconditions.checkArgument(alphabet.length() > 0, "Empty alphabet");
     try {
       ByteBuffer buffer = StandardCharsets.US_ASCII.newEncoder().encode(CharBuffer.wrap(alphabet));
@@ -113,7 +114,7 @@
   }
 
   private Iterable<BitStream> encodePerImpl(boolean aligned) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
 
     int characterBitCount = calculateBitsPerCharacter(aligned);
 
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Integer.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Integer.java
index 9b29c98..921d2d3 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Integer.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Integer.java
@@ -24,6 +24,7 @@
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
 import java.util.Collection;
+import java.util.Objects;
 
 import javax.annotation.Nullable;
 
@@ -79,7 +80,7 @@
   }
 
   private void validateValue() {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     Preconditions.checkState(
         minimumValue == null || value.compareTo(minimumValue) >= 0,
         "Too small value %s", value);
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1ObjectIdentifier.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1ObjectIdentifier.java
index 946b9a4..0ddfc59 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1ObjectIdentifier.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1ObjectIdentifier.java
@@ -16,7 +16,6 @@
 
 package android.location.cts.asn1.base;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
@@ -24,6 +23,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Object identifiers are similar in concept to URIs (indeed
@@ -70,7 +70,7 @@
   }
 
   private byte[] encodeBerInternal() {
-    Preconditions.checkNotNull(value);
+    Objects.requireNonNull(value);
     // Encode according to BER.
     BitStream basicEncoding = new BitStream();
     Iterator<Integer> valueIterator = value.iterator();
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1OctetString.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1OctetString.java
index c47f739..fe0ee03 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1OctetString.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1OctetString.java
@@ -24,6 +24,7 @@
 
 import java.nio.ByteBuffer;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  * Implements ASN.1 functionality.
@@ -63,12 +64,12 @@
   }
 
   @Override int getBerValueLength() {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     return value.length;
   }
 
   @Override void encodeBerValue(ByteBuffer buf) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     buf.put(value);
   }
 
@@ -77,7 +78,7 @@
   }
 
   private Iterable<BitStream> encodePerImpl(boolean aligned) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     Preconditions.checkState(
         maximumSize == null || value.length <= maximumSize, "Too large %s",
         value.length);
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Utf8String.java b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Utf8String.java
index 513c02c..0e04b7b 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Utf8String.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/asn1/base/Asn1Utf8String.java
@@ -22,6 +22,7 @@
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  * Base class for representing ASN.1 objects of type UTF8String.
@@ -67,12 +68,12 @@
   }
 
   @Override int getBerValueLength() {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     return getValueBytes().length;
   }
 
   @Override void encodeBerValue(ByteBuffer buf) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     buf.put(getValueBytes());
   }
 
@@ -81,7 +82,7 @@
   }
 
   private Iterable<BitStream> encodePerImpl(boolean aligned) {
-    Preconditions.checkNotNull(value, "No value set.");
+    Objects.requireNonNull(value, "No value set.");
     Preconditions.checkState(
         maximumSize == null || value.length() <= maximumSize, "Too large %s",
         value.length());
diff --git a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
index de946b3..8d6b83e 100644
--- a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
+++ b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
@@ -388,13 +388,18 @@
                 && !pm.hasSystemFeature("android.hardware.type.watch");
     }
 
+    public File getVolumePath(String volumeName) {
+        return mContext.getSystemService(StorageManager.class)
+                .getStorageVolume(MediaStore.Files.getContentUri(volumeName)).getDirectory();
+    }
+
     private void prepareFile() throws Exception {
-        final File dir = new File(MediaStore.getVolumePath(mVolumeName),
+        final File dir = new File(getVolumePath(mVolumeName),
                 Environment.DIRECTORY_DOCUMENTS);
         final File file = new File(dir, "cts" + System.nanoTime() + ".txt");
 
         mFile = stageFile(R.raw.text, file);
-        mMediaStoreUri = MediaStore.scanFile(mContext, mFile);
+        mMediaStoreUri = MediaStore.scanFile(mContext.getContentResolver(), mFile);
 
         Log.v(TAG, "Staged " + mFile + " as " + mMediaStoreUri);
     }
diff --git a/tests/tests/appop/AndroidManifest.xml b/tests/tests/appop/AndroidManifest.xml
index 4e8aea9..616647a 100644
--- a/tests/tests/appop/AndroidManifest.xml
+++ b/tests/tests/appop/AndroidManifest.xml
@@ -20,6 +20,8 @@
     package="android.app.appops.cts"
     android:targetSandboxVersion="2">
   <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+  <uses-permission android:name="android.permission.BLUETOOTH" />
 
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
   <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
index d20b00d..9601d21 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
@@ -33,6 +33,7 @@
 import android.app.SyncNotedAppOp
 import android.app.WallpaperManager
 import android.app.WallpaperManager.FLAG_SYSTEM
+import android.bluetooth.BluetoothManager
 import android.content.BroadcastReceiver
 import android.content.ComponentName
 import android.content.ContentValues
@@ -41,6 +42,7 @@
 import android.content.Intent
 import android.content.IntentFilter
 import android.content.ServiceConnection
+import android.content.pm.PackageManager.FEATURE_BLUETOOTH
 import android.content.pm.PackageManager.FEATURE_TELEPHONY
 import android.hardware.camera2.CameraDevice
 import android.hardware.camera2.CameraManager
@@ -415,6 +417,27 @@
     }
 
     /**
+     * Realistic end-to-end test for scanning bluetooth
+     */
+    @Test
+    fun getBTScanResults() {
+        assumeTrue("Device does not support bluetooth",
+                context.packageManager.hasSystemFeature(FEATURE_BLUETOOTH))
+
+        val btManager = context.createFeatureContext(TEST_FEATURE_ID)
+                .getSystemService(BluetoothManager::class.java)
+
+        btManager.adapter.startDiscovery()
+        try {
+            assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
+            assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+            assertThat(noted[0].second.map { it.methodName }).contains("getBTScanResults")
+        } finally {
+            btManager.adapter.cancelDiscovery()
+        }
+    }
+
+    /**
      * Realistic end-to-end test for getting last location
      */
     @Test
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index d15ec1d..2608830 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -247,6 +247,14 @@
   EXPECT_EQ(toString(static_cast<IntEnum>(-1)), "-1");
 }
 
+TEST_P(NdkBinderTest_Aidl, EnumValues) {
+  auto range = ::ndk::enum_range<ByteEnum>();
+  auto iter = range.begin();
+  EXPECT_EQ(ByteEnum::FOO, *iter++);
+  EXPECT_EQ(ByteEnum::BAR, *iter++);
+  EXPECT_EQ(range.end(), iter);
+}
+
 TEST_P(NdkBinderTest_Aidl, RepeatBinder) {
   SpAIBinder binder = iface->asBinder();
   SpAIBinder ret;
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
index 7a7e536..ef3ad7a 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
@@ -15,6 +15,9 @@
  */
 #define LOG_TAG "Cts-NdkBinderTest"
 
+#include "utilities.h"
+
+#include <android/binder_auto_utils.h>
 #include <android/binder_status.h>
 #include <gtest/gtest.h>
 
@@ -193,3 +196,20 @@
     AStatus_delete(status);
   }
 }
+
+TEST(NdkBinderTest_AStatus, StatusDescription) {
+  using ndk::ScopedAStatus;
+
+  EXPECT_TRUE(
+      ContainsSubstring(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED).getDescription(),
+                        "TRANSACTION_FAILED"));
+  EXPECT_TRUE(ContainsSubstring(
+      ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED, "asdf").getDescription(),
+      "asdf"));
+  EXPECT_TRUE(
+      ContainsSubstring(ScopedAStatus::fromServiceSpecificError(42).getDescription(), "42"));
+  EXPECT_TRUE(ContainsSubstring(
+      ScopedAStatus::fromServiceSpecificErrorWithMessage(42, "asdf").getDescription(), "asdf"));
+  EXPECT_TRUE(
+      ContainsSubstring(ScopedAStatus::fromStatus(STATUS_BAD_TYPE).getDescription(), "BAD_TYPE"));
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
index e9d6ad5..009ff31 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
@@ -48,6 +48,15 @@
   return ::testing::AssertionFailure() << "Status: " << t;
 }
 
+inline ::testing::AssertionResult ContainsSubstring(const std::string& s, const std::string& ss) {
+  if (s.find(ss) != std::string::npos) {
+    return ::testing::AssertionSuccess();
+  } else {
+    return ::testing::AssertionFailure()
+           << "String: '" << s << "' does not contain substring: " << ss;
+  }
+}
+
 #define EXPECT_OK(THING) EXPECT_TRUE(isOk(THING))
 #define ASSERT_OK(THING) ASSERT_TRUE(isOk(THING))
 
diff --git a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
index ceabc3d..bed372c 100644
--- a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.car.Car;
+import android.car.VehicleAreaSeat;
 import android.car.VehicleAreaType;
 import android.car.VehiclePropertyIds;
 import android.car.hardware.CarPropertyConfig;
@@ -110,17 +111,63 @@
         mPropertyIds.add(VehiclePropertyIds.PERF_VEHICLE_SPEED);
         mPropertyIds.add(VehiclePropertyIds.GEAR_SELECTION);
         mPropertyIds.add(VehiclePropertyIds.NIGHT_MODE);
+        mPropertyIds.add(VehiclePropertyIds.PARKING_BRAKE_ON);
     }
 
+    /**
+     * Test for {@link CarPropertyManager#getPropertyList()}
+     */
     @Test
     public void testGetPropertyList() {
         List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList();
         assertNotNull(allConfigs);
+    }
+
+    /**
+     * Test for {@link CarPropertyManager#getPropertyList(ArraySet)}
+     */
+    @Test
+    public void testGetPropertyListWithArraySet() {
         List<CarPropertyConfig> requiredConfigs = mCarPropertyManager.getPropertyList(mPropertyIds);
         // Vehicles need to implement all of those properties
         assertEquals(mPropertyIds.size(), requiredConfigs.size());
     }
 
+    /**
+     * Test for {@link CarPropertyManager#getCarPropertyConfig(int)}
+     */
+    @Test
+    public void testGetPropertyConfig() {
+        List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList();
+        for (CarPropertyConfig cfg : allConfigs) {
+            assertNotNull(mCarPropertyManager.getCarPropertyConfig(cfg.getPropertyId()));
+        }
+    }
+
+    /**
+     * Test for {@link CarPropertyManager#getAreaId(int, int)}
+     */
+    @Test
+    public void testGetAreaId() {
+        // For global properties, getAreaId should always return 0.
+        List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList();
+        for (CarPropertyConfig cfg : allConfigs) {
+            if (cfg.isGlobalProperty()) {
+                assertEquals(0, mCarPropertyManager.getAreaId(cfg.getPropertyId(),
+                        VehicleAreaSeat.SEAT_ROW_1_LEFT));
+            } else {
+                int[] areaIds = cfg.getAreaIds();
+                // Because areaId in propConfig must not be overlapped with each other.
+                // The result should be itself.
+                for (int areaIdInConfig : areaIds) {
+                    int areaIdByCarPropertyManager =
+                            mCarPropertyManager.getAreaId(cfg.getPropertyId(), areaIdInConfig);
+                    assertEquals(areaIdInConfig, areaIdByCarPropertyManager);
+                }
+            }
+        }
+    }
+
     @CddTest(requirement="2.5.1")
     @Test
     public void testMustSupportGearSelection() throws Exception {
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index e73c11a..73897fd 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -36,8 +36,8 @@
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.Build;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.ParcelUuid;
@@ -278,11 +278,15 @@
         if (mTelephonyManager.getPhoneCount() == 1) {
             return;
         }
+
+        /* TODO: b/145993690 */
         if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
-            fail("This test requires two SIM cards.");
+            /* This test requires two SIM cards */
+            return;
         }
         if (subIdWithCarrierPrivilege == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            failMessage();
+            /* This test requires SIM with carrier privilege */
+            return;
         }
 
         List<SubscriptionInfo> subscriptionInfoList =
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java
index dc49a2e..fa0572c 100644
--- a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java
@@ -17,6 +17,7 @@
 package android.provider.cts.contacts;
 
 
+import android.accounts.Account;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -120,6 +121,14 @@
                 lookupContact.getId(), rawContact.load().getContactId());
     }
 
+    public void testGetDeviceAccountNameAndType_haveSameNullness() {
+        String name = RawContacts.getLocalAccountName(mContext);
+        String type = RawContacts.getLocalAccountType(mContext);
+
+        assertTrue("Device account name and type must both be null or both be non-null",
+                (name == null && type == null) || (name != null && type != null));
+    }
+
     public void testRawContactDelete_setsDeleteFlag() {
         long rawContactid = RawContactUtil.insertRawContact(mResolver,
                 StaticAccountAuthenticator.ACCOUNT_1);
@@ -142,7 +151,11 @@
     }
 
     public void testRawContactDelete_localDeleteRemovesRecord() {
-        long rawContactid = RawContactUtil.insertRawContact(mResolver, null);
+        String name = RawContacts.getLocalAccountName(mContext);
+        String type = RawContacts.getLocalAccountType(mContext);
+        Account account = name != null && type != null ? new Account(name, type) : null;
+
+        long rawContactid = RawContactUtil.insertRawContact(mResolver, account);
         assertTrue(RawContactUtil.rawContactExistsById(mResolver, rawContactid));
 
         // Local raw contacts should be deleted immediately even if isSyncAdapter=false
@@ -179,6 +192,32 @@
         RawContactUtil.delete(mResolver, ids.mRawContactId, true);
     }
 
+    /**
+     * The local account is the default if a raw contact insert does not specify a value for
+     * {@link RawContacts#ACCOUNT_NAME} and {@link RawContacts#ACCOUNT_TYPE}.
+     *
+     * <p>The values returned by {@link RawContacts#getLocalAccountName()} and
+     * {@link RawContacts#getLocalAccountType()} can be  customized by overriding the
+     * config_rawContactsLocalAccountName and config_rawContactsLocalAccountType resource strings 
+     * defined in platform/frameworks/base/core/res/res/values/config.xml.
+     */
+    public void testRawContactCreate_noAccountUsesLocalAccount() {
+        // Save a raw contact without an account.
+        long rawContactid = RawContactUtil.insertRawContact(mResolver, null);
+
+        String[] row =  RawContactUtil.queryByRawContactId(mResolver, rawContactid,
+                new String[] {
+                        RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE
+                });
+
+        // When no account is specified the contact is created in the local account.
+        assertEquals(RawContacts.getLocalAccountName(mContext), row[0]);
+        assertEquals(RawContacts.getLocalAccountType(mContext), row[1]);
+
+        // Clean up
+        RawContactUtil.delete(mResolver, rawContactid, true);
+    }
+
     public void testRawContactUpdate_updatesContactUpdatedTimestamp() {
         DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
 
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java
index 4f82a49..ceaee73 100755
--- a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java
@@ -20,6 +20,7 @@
 import android.accounts.AccountManager;
 import android.content.ContentResolver;
 import android.os.SystemClock;
+import android.provider.ContactsContract;
 import android.provider.cts.contacts.DatabaseAsserts.ContactIdPair;
 import android.provider.cts.contacts.account.StaticAccountAuthenticator;
 import android.test.AndroidTestCase;
@@ -100,6 +101,34 @@
     }
 
     /**
+     * Contacts saved to the local account should not be removed when accounts change.
+     *
+     * <p>The local account is a special case that is not added to
+     * {@link AccountManager}. Normally raw contacts with an
+     * {@link android.provider.ContactsContract.RawContacts#ACCOUNT_NAME} and
+     * {@link android.provider.ContactsContract.RawContacts#ACCOUNT_TYPE} that do not correspond
+     * to an added account will be removed but this should not be done for the local account.
+     */
+    public void testAccountRemoval_doesNotDeleteLocalAccountContacts() {
+        mAccountManager.addAccountExplicitly(ACCT_1, null, null);
+        ArrayList<ContactIdPair> acc1Ids = createContacts(ACCT_1, 5);
+
+        String name = ContactsContract.RawContacts.getLocalAccountName(mContext);
+        String type = ContactsContract.RawContacts.getLocalAccountType(mContext);
+        Account deviceAccount = name != null && type != null ? new Account(name, type) : null;
+        long deviceRawContactId = RawContactUtil
+                .createRawContactWithAutoGeneratedName(mResolver, deviceAccount);
+
+        mAccountManager.removeAccount(ACCT_1, null, null);
+
+        // Wait for deletion of the contacts in the removed account to finish before verifying
+        // the existence of the device contacts
+        assertContactsDeletedEventually(System.currentTimeMillis(), acc1Ids);
+
+        assertTrue(RawContactUtil.rawContactExistsById(mResolver, deviceRawContactId));
+    }
+
+    /**
      * Contact has merged raw contacts from different accounts. Contact should not be deleted when
      * one account is removed.  But contact should have last updated timestamp updated.
      */
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 5ad911f..1198ef8 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -281,11 +281,17 @@
     }
 
     public void testAlarmClockDismissAlarm() {
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+            return;
+        }
         Intent intent = new Intent(AlarmClock.ACTION_DISMISS_ALARM);
         assertCanBeHandled(intent);
     }
 
     public void testAlarmClockSnoozeAlarm() {
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+            return;
+        }
         Intent intent = new Intent(AlarmClock.ACTION_SNOOZE_ALARM);
         intent.putExtra(AlarmClock.EXTRA_ALARM_SNOOZE_DURATION, 10);
         assertCanBeHandled(intent);
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index 336c492..03ae82f 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -18,9 +18,12 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.app.Activity;
 import android.app.AppOpsManager;
 import android.app.Instrumentation;
+import android.app.WallpaperManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -783,6 +786,8 @@
     }
 
     public void testAccessWallpaper() throws IOException, InterruptedException {
+        assumeWallpaperSupported();
+
         // set Wallpaper by context#setWallpaper(Bitmap)
         Bitmap bitmap = Bitmap.createBitmap(20, 30, Bitmap.Config.RGB_565);
         // Test getWallpaper
@@ -1089,6 +1094,8 @@
     }
 
     public void testGetWallpaperDesiredMinimumHeightAndWidth() {
+        assumeWallpaperSupported();
+
         int height = mContext.getWallpaperDesiredMinimumHeight();
         int width = mContext.getWallpaperDesiredMinimumWidth();
 
@@ -1608,4 +1615,9 @@
         } catch (IllegalArgumentException expected) {
         }
     }
+
+    private void assumeWallpaperSupported() {
+        assumeTrue("Device does not support wallpapers",
+                WallpaperManager.getInstance(mContext).isWallpaperSupported());
+    }
 }
diff --git a/tests/tests/cronet/Android.bp b/tests/tests/cronet/Android.bp
new file mode 100644
index 0000000..0b50579
--- /dev/null
+++ b/tests/tests/cronet/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+// TODO: Move this target to cts/tests/tests/net/cronet
+android_test {
+    name: "CtsCronetTestCases",
+    defaults: ["cts_defaults"],
+
+    // Include both the 32 and 64 bit versions
+    compile_multilib: "both",
+
+    static_libs: [
+        "CronetApiCommonTests",
+        "ctstestrunner-axt",
+    ],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "mts",
+    ],
+
+}
diff --git a/tests/tests/cronet/AndroidManifest.xml b/tests/tests/cronet/AndroidManifest.xml
new file mode 100644
index 0000000..b7ae844
--- /dev/null
+++ b/tests/tests/cronet/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cronet.cts" >
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application android:usesCleartextTraffic="true">
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.chromium.net.cronet" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.cronet.cts"
+                     android:label="CTS tests of android.cronet">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/cronet/AndroidTest.xml b/tests/tests/cronet/AndroidTest.xml
new file mode 100644
index 0000000..79c37f7
--- /dev/null
+++ b/tests/tests/cronet/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Cronet test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsCronetTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.cronet.cts" />
+        <option name="runtime-hint" value="10s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/cronet/OWNERS b/tests/tests/cronet/OWNERS
new file mode 100644
index 0000000..f4525df
--- /dev/null
+++ b/tests/tests/cronet/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 31808
+include ../net/OWNERS
\ No newline at end of file
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 317acc0..fe13ea4 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -1533,9 +1533,59 @@
         }
     }
 
+    // One static PNG and one animated GIF to test setting invalid crop rects,
+    // to test both paths (animated and non-animated) through ImageDecoder.
+    private static Object[] resourcesForCropTests() {
+        return new Object[] { R.drawable.png_test, R.drawable.animated };
+    }
+
     @Test(expected = IllegalStateException.class)
-    public void testCropNegativeLeft() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
+    @Parameters(method = "resourcesForCropTests")
+    public void testInvertCropWidth(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
+        try {
+            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                // This rect is unsorted.
+                decoder.setCrop(new Rect(info.getSize().getWidth(), 0, 0,
+                                         info.getSize().getHeight()));
+            });
+        } catch (IOException e) {
+            fail("Failed with exception " + e);
+        }
+    }
+
+    @Test(expected = IllegalStateException.class)
+    @Parameters(method = "resourcesForCropTests")
+    public void testInvertCropHeight(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
+        try {
+            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                // This rect is unsorted.
+                decoder.setCrop(new Rect(0, info.getSize().getWidth(),
+                                         info.getSize().getHeight(), 0));
+            });
+        } catch (IOException e) {
+            fail("Failed with exception " + e);
+        }
+    }
+
+    @Test(expected = IllegalStateException.class)
+    @Parameters(method = "resourcesForCropTests")
+    public void testEmptyCrop(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
+        try {
+            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                decoder.setCrop(new Rect(1, 1, 1, 1));
+            });
+        } catch (IOException e) {
+            fail("Failed with exception " + e);
+        }
+    }
+
+    @Test(expected = IllegalStateException.class)
+    @Parameters(method = "resourcesForCropTests")
+    public void testCropNegativeLeft(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
                 decoder.setCrop(new Rect(-1, 0, info.getSize().getWidth(),
@@ -1547,21 +1597,9 @@
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testCropNegativeLeftAnimated() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.animated);
-        try {
-            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                decoder.setCrop(new Rect(-1, 0, info.getSize().getWidth(),
-                                                info.getSize().getHeight()));
-            });
-        } catch (IOException e) {
-            fail("Failed with exception " + e);
-        }
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testCropNegativeTop() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
+    @Parameters(method = "resourcesForCropTests")
+    public void testCropNegativeTop(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
                 decoder.setCrop(new Rect(0, -1, info.getSize().getWidth(),
@@ -1573,21 +1611,9 @@
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testCropNegativeTopAnimated() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.animated);
-        try {
-            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                decoder.setCrop(new Rect(0, -1, info.getSize().getWidth(),
-                                                info.getSize().getHeight()));
-            });
-        } catch (IOException e) {
-            fail("Failed with exception " + e);
-        }
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testCropTooWide() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
+    @Parameters(method = "resourcesForCropTests")
+    public void testCropTooWide(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
                 decoder.setCrop(new Rect(1, 0, info.getSize().getWidth() + 1,
@@ -1598,22 +1624,11 @@
         }
     }
 
-    @Test(expected = IllegalStateException.class)
-    public void testCropTooWideAnimated() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.animated);
-        try {
-            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                decoder.setCrop(new Rect(1, 0, info.getSize().getWidth() + 1,
-                                               info.getSize().getHeight()));
-            });
-        } catch (IOException e) {
-            fail("Failed with exception " + e);
-        }
-    }
 
     @Test(expected = IllegalStateException.class)
-    public void testCropTooTall() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
+    @Parameters(method = "resourcesForCropTests")
+    public void testCropTooTall(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
                 decoder.setCrop(new Rect(0, 1, info.getSize().getWidth(),
@@ -1625,23 +1640,9 @@
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testCropResize() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
-        try {
-            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                Size size = info.getSize();
-                decoder.setTargetSize(size.getWidth() / 2, size.getHeight() / 2);
-                decoder.setCrop(new Rect(0, 0, size.getWidth(),
-                                               size.getHeight()));
-            });
-        } catch (IOException e) {
-            fail("Failed with exception " + e);
-        }
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testCropResizeAnimated() {
-        ImageDecoder.Source src = mCreators[0].apply(R.drawable.animated);
+    @Parameters(method = "resourcesForCropTests")
+    public void testCropResize(int resId) {
+        ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
                 Size size = info.getSize();
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index cfb3af6..b4a4320 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -34,7 +34,6 @@
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.cts.R;
 import android.graphics.drawable.Drawable.ConstantState;
@@ -720,6 +719,7 @@
 
         GradientDrawable drawable = (GradientDrawable)
                 context.getDrawable(R.drawable.gradientdrawable_mix_theme);
+
         // Verify that despite multiple inflation passes are done to inflate both
         // the non-theme attributes as well as the themed attributes
         assertEquals(GradientDrawable.RADIAL_GRADIENT, drawable.getGradientType());
@@ -765,27 +765,6 @@
                 Orientation.LEFT_RIGHT);
     }
 
-    @Test
-    public void testTintedStrokeWithoutSolidColor() {
-        final Context context = InstrumentationRegistry.getTargetContext();
-        GradientDrawable strokeDrawable = (GradientDrawable)
-                context.getDrawable(R.drawable.gradientdrawable_stroke_tint);
-        int bgColor = context.getColor(android.R.color.holo_blue_light);
-        int tintColor = context.getColor(android.R.color.holo_orange_light);
-        int width = 100;
-        int height = 100;
-        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        canvas.drawColor(bgColor);
-        strokeDrawable.setTint(tintColor);
-        strokeDrawable.setTintMode(PorterDuff.Mode.MULTIPLY);
-        strokeDrawable.setBounds(0, 0, width, height);
-        strokeDrawable.draw(canvas);
-
-        assertEquals(bitmap.getPixel(width / 2, height / 2), bgColor);
-        assertEquals(bitmap.getPixel(2, height / 2), tintColor);
-    }
-
     private void verifyGradientOrientation(int resId, Orientation expected) {
         final Context context = InstrumentationRegistry.getTargetContext();
         assertEquals(expected,
diff --git a/tests/tests/hardware/res/raw/razer_serval_keyeventtests.json b/tests/tests/hardware/res/raw/razer_serval_keyeventtests.json
new file mode 100644
index 0000000..eed99d7
--- /dev/null
+++ b/tests/tests/hardware/res/raw/razer_serval_keyeventtests.json
@@ -0,0 +1,157 @@
+[
+  {
+    "name": "Press BUTTON_A",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_A"},
+      {"action": "UP", "keycode": "BUTTON_A"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_B",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_B"},
+      {"action": "UP", "keycode": "BUTTON_B"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_X",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x48, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_X"},
+      {"action": "UP", "keycode": "BUTTON_X"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_Y",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x88, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_Y"},
+      {"action": "UP", "keycode": "BUTTON_Y"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_L1",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x01, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_L1"},
+      {"action": "UP", "keycode": "BUTTON_L1"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_R1",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x02, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_R1"},
+      {"action": "UP", "keycode": "BUTTON_R1"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_THUMBL",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x10, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_THUMBL"},
+      {"action": "UP", "keycode": "BUTTON_THUMBL"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_THUMBR",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x20, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_THUMBR"},
+      {"action": "UP", "keycode": "BUTTON_THUMBR"}
+    ]
+  },
+
+  {
+    "name": "Press arrow left button (the button left of 'power key')",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x01, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_SELECT"},
+      {"action": "UP", "keycode": "BUTTON_SELECT"}
+    ]
+  },
+
+  {
+    "name": "Press 'power key'",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x40, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_MODE"},
+      {"action": "UP", "keycode": "BUTTON_MODE"}
+    ]
+  },
+
+  {
+    "name": "Press arrow right button (the button right of 'power key')",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x08, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_START"},
+      {"action": "UP", "keycode": "BUTTON_START"}
+    ]
+  },
+
+  {
+    "name": "Press BACK button (left arrow at the bottom of the controller)",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "GAMEPAD | KEYBOARD",
+    "events": [
+      {"action": "DOWN", "keycode": "BACK"},
+      {"action": "UP", "keycode": "BACK"}
+    ]
+  }
+]
\ No newline at end of file
diff --git a/tests/tests/hardware/res/raw/razer_serval_motioneventtests.json b/tests/tests/hardware/res/raw/razer_serval_motioneventtests.json
new file mode 100644
index 0000000..868277c
--- /dev/null
+++ b/tests/tests/hardware/res/raw/razer_serval_motioneventtests.json
@@ -0,0 +1,193 @@
+[
+  {
+    "name": "Sanity check - should not produce any events",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "events": []
+  },
+
+  {
+    "name": "Press left DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Press right DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Press up DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
+    ]
+  },
+
+  {
+    "name": "Press down DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press left",
+    "reports": [
+      [0x01, 0x00, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_X": -1}},
+      {"action": "MOVE", "axes": {"AXIS_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press right",
+    "reports": [
+      [0x01, 0xff, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_X": 1}},
+      {"action": "MOVE", "axes": {"AXIS_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press up",
+    "reports": [
+      [0x01, 0x80, 0x00, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_Y": -1}},
+      {"action": "MOVE", "axes": {"AXIS_Y": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press down",
+    "reports": [
+      [0x01, 0x80, 0xff, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_X": 0, "AXIS_Y": 1, "AXIS_Z": 0}},
+      {"action": "MOVE", "axes": {"AXIS_X": 0, "AXIS_Y": 0, "AXIS_Z": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press left",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_Z": -1}},
+      {"action": "MOVE", "axes": {"AXIS_Z": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press right",
+    "reports": [
+      [0x01, 0x80, 0x80, 0xff, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_Z": 1}},
+      {"action": "MOVE", "axes": {"AXIS_Z": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press up",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_RZ": -1}},
+      {"action": "MOVE", "axes": {"AXIS_RZ": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press down",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0xff, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_RZ": 1}},
+      {"action": "MOVE", "axes": {"AXIS_RZ": 0}}
+    ]
+  },
+
+  {
+    "name": "Left trigger - quick press",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0xff, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},
+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0, "AXIS_BRAKE": 0}}
+    ]
+  },
+
+  {
+    "name": "Right trigger - quick press",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0xff, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xff]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},
+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0, "AXIS_GAS": 0}}
+    ]
+  }
+
+
+]
\ No newline at end of file
diff --git a/tests/tests/hardware/res/raw/razer_serval_register.json b/tests/tests/hardware/res/raw/razer_serval_register.json
new file mode 100644
index 0000000..3d8bb96
--- /dev/null
+++ b/tests/tests/hardware/res/raw/razer_serval_register.json
@@ -0,0 +1,24 @@
+{
+  "id": 1,
+  "command": "register",
+  "name": "Razer Serval (Test)",
+  "vid": 0x1532,
+  "pid": 0x0900,
+  "descriptor": [
+    0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0xa1, 0x02, 0x85, 0x01, 0x75, 0x08, 0x95, 0x04,
+    0x15, 0x00, 0x26, 0xff, 0x00, 0x09, 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x81,
+    0x02, 0x75, 0x04, 0x95, 0x01, 0x15, 0x00, 0x25, 0x07, 0x09, 0x39, 0x81, 0x42, 0x75,
+    0x01, 0x95, 0x01, 0x15, 0x00, 0x25, 0x01, 0x05, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09,
+    0x02, 0x81, 0x02, 0x09, 0x04, 0x81, 0x02, 0x09, 0x05, 0x81, 0x02, 0x09, 0x07, 0x81,
+    0x02, 0x09, 0x08, 0x81, 0x02, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x81, 0x02, 0x05, 0x09,
+    0x09, 0x0c, 0x81, 0x02, 0x09, 0x0e, 0x81, 0x02, 0x09, 0x0f, 0x81, 0x02, 0x09, 0x0d,
+    0x81, 0x02, 0x05, 0x0c, 0x0a, 0x23, 0x02, 0x81, 0x02, 0x05, 0x09, 0x09, 0x0b, 0x81,
+    0x02, 0x75, 0x07, 0x95, 0x01, 0x81, 0x03, 0x75, 0x08, 0x95, 0x02, 0x15, 0x00, 0x26,
+    0xff, 0x00, 0x05, 0x02, 0x09, 0xc5, 0x09, 0xc4, 0x81, 0x02, 0x75, 0x08, 0x95, 0x01,
+    0x15, 0x00, 0x26, 0xff, 0x00, 0x05, 0x06, 0x09, 0x20, 0x81, 0x02, 0xc0, 0x05, 0xff,
+    0x09, 0x02, 0x15, 0x00, 0x25, 0xff, 0x75, 0x08, 0x95, 0x5a, 0xb1, 0x01, 0x05, 0x07,
+    0x85, 0x02, 0x05, 0x08, 0x09, 0x01, 0x09, 0x02, 0x09, 0x03, 0x09, 0x04, 0x09, 0x4f,
+    0x09, 0x50, 0x09, 0x51, 0x09, 0x52, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08,
+    0x91, 0x02, 0xc0
+  ]
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/RazerServalTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/RazerServalTest.java
new file mode 100644
index 0000000..2122085
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/RazerServalTest.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.hardware.input.cts.tests;
+
+import android.hardware.cts.R;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class RazerServalTest extends InputTestCase {
+    public RazerServalTest() {
+        super(R.raw.razer_serval_register);
+    }
+
+    /**
+     * Test all keys except the home key.
+     */
+    @Test
+    public void testAllKeys() {
+        testInputEvents(R.raw.razer_serval_keyeventtests);
+    }
+
+    @Test
+    public void testAllMotions() {
+        testInputEvents(R.raw.razer_serval_motioneventtests);
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 7e8be97..0847800 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -64,6 +64,7 @@
 import android.security.keystore.KeyProperties;
 import android.test.AndroidTestCase;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.google.common.collect.ImmutableSet;
 
@@ -99,6 +100,8 @@
  */
 public class KeyAttestationTest extends AndroidTestCase {
 
+    private static final String TAG = AndroidKeyStoreTest.class.getSimpleName();
+
     private static final int ORIGINATION_TIME_OFFSET = 1000000;
     private static final int CONSUMPTION_TIME_OFFSET = 2000000;
 
@@ -880,7 +883,8 @@
         RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
         assertNotNull(rootOfTrust);
         assertNotNull(rootOfTrust.getVerifiedBootKey());
-        assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32);
+        assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
+                   " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
         checkEntropy(rootOfTrust.getVerifiedBootKey());
         if (requireLocked) {
             assertTrue(rootOfTrust.isDeviceLocked());
@@ -889,8 +893,8 @@
     }
 
     private void checkEntropy(byte[] verifiedBootKey) {
-        assertTrue(checkShannonEntropy(verifiedBootKey));
-        assertTrue(checkTresBiEntropy(verifiedBootKey));
+        assertTrue("Failed Shannon entropy check", checkShannonEntropy(verifiedBootKey));
+        assertTrue("Failed BiEntropy check", checkTresBiEntropy(verifiedBootKey));
     }
 
     private boolean checkShannonEntropy(byte[] verifiedBootKey) {
@@ -900,8 +904,10 @@
 
     private double calculateShannonEntropy(double probabilityOfSetBit) {
         if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0;
-        return (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
-               ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
+        double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
+                            ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
+        Log.i(TAG, "Shannon entropy of VB Key: " + entropy);
+        return entropy;
     }
 
     private boolean checkTresBiEntropy(byte[] verifiedBootKey) {
@@ -917,6 +923,7 @@
             length -= 1;
         }
         double tresBiEntropy = (1 / weightingFactor) * weightedEntropy;
+        Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy);
         return tresBiEntropy > 0.9;
     }
 
diff --git a/tests/tests/media/res/raw/sinesweepwav24.wav b/tests/tests/media/res/raw/sinesweepwav24.wav
new file mode 100644
index 0000000..2657b5c
--- /dev/null
+++ b/tests/tests/media/res/raw/sinesweepwav24.wav
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
index c2c2a34..47b75bf 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
@@ -489,6 +489,8 @@
             // Stopping one AR must allow creating a new one
             audioRecords.peek().stop();
             audioRecords.pop().release();
+            final long SLEEP_AFTER_STOP_FOR_INACTIVITY_MS = 1000;
+            Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
             audioRecords.push(createDefaultPlaybackCaptureRecord());
 
             // That new one must still be able to capture
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 7f51672..22549e5 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -172,6 +172,10 @@
         decode(R.raw.sinesweepwav, 0.0f);
         testTimeStampOrdering(R.raw.sinesweepwav);
     }
+    public void testDecodeWav24() throws Exception {
+        decode(R.raw.sinesweepwav24, 0.0f);
+        testTimeStampOrdering(R.raw.sinesweepwav24);
+    }
     public void testDecodeFlacMkv() throws Exception {
         decode(R.raw.sinesweepflacmkv, 0.0f);
         testTimeStampOrdering(R.raw.sinesweepflacmkv);
@@ -3488,7 +3492,8 @@
         assertTrue("No video track was found", trackIndex >= 0);
 
         extractor.selectTrack(trackIndex);
-        format.setFeatureEnabled(MediaFormat.KEY_LOW_LATENCY, true /* enable */);
+        format.setFeatureEnabled(MediaCodecInfo.CodecCapabilities.FEATURE_LowLatency,
+                true /* enable */);
 
         MediaCodecList mcl = new MediaCodecList(MediaCodecList.ALL_CODECS);
         String decoderName = mcl.findDecoderForFormat(format);
@@ -3506,6 +3511,8 @@
         } else {
             decoder = new SdkMediaCodec(MediaCodec.createByCodecName(decoderName));
         }
+        format.removeFeature(MediaCodecInfo.CodecCapabilities.FEATURE_LowLatency);
+        format.setInteger(MediaFormat.KEY_LOW_LATENCY, 1);
         decoder.configure(format, 0 /* flags */, surface);
         decoder.start();
 
diff --git a/tests/tests/media/src/android/media/cts/HeifWriterTest.java b/tests/tests/media/src/android/media/cts/HeifWriterTest.java
index 79eda3b..068a5e7 100644
--- a/tests/tests/media/src/android/media/cts/HeifWriterTest.java
+++ b/tests/tests/media/src/android/media/cts/HeifWriterTest.java
@@ -40,28 +40,38 @@
 import android.os.HandlerThread;
 import android.os.Process;
 import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.RequiresDevice;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.heifwriter.HeifWriter;
+import androidx.test.filters.SmallTest;
 
 import com.android.compatibility.common.util.MediaUtils;
 
 import java.io.Closeable;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.RandomAccessFile;
 import java.util.Arrays;
 
+@SmallTest
+@RequiresDevice
 @AppModeFull(reason = "Instant apps cannot access the SD card")
 public class HeifWriterTest extends AndroidTestCase {
     private static final String TAG = HeifWriterTest.class.getSimpleName();
     private static final boolean DEBUG = false;
+    private static final boolean DUMP_OUTPUT = false;
     private static final boolean DUMP_YUV_INPUT = false;
     private static final int GRID_WIDTH = 512;
     private static final int GRID_HEIGHT = 512;
@@ -349,8 +359,13 @@
                 mHeight = 1080;
                 mRotation = 0;
                 mQuality = 100;
-                mOutputPath = new File(Environment.getExternalStorageDirectory(),
-                        OUTPUT_FILENAME).getAbsolutePath();
+                // use memfd by default
+                if (DUMP_OUTPUT) {
+                    mOutputPath = new File(Environment.getExternalStorageDirectory(),
+                            OUTPUT_FILENAME).getAbsolutePath();
+                } else {
+                    mOutputPath = null;
+                }
             }
 
             Builder setInputPath(String inputPath) {
@@ -395,9 +410,11 @@
             }
 
             private void cleanupStaleOutputs() {
-                File outputFile = new File(mOutputPath);
-                if (outputFile.exists()) {
-                    outputFile.delete();
+                if (mOutputPath != null) {
+                    File outputFile = new File(mOutputPath);
+                    if (outputFile.exists()) {
+                        outputFile.delete();
+                    }
                 }
             }
 
@@ -434,13 +451,22 @@
 
         mInputIndex = 0;
         HeifWriter heifWriter = null;
-        FileInputStream inputStream = null;
-        FileOutputStream outputStream = null;
+        FileInputStream inputYuvStream = null;
+        FileOutputStream outputYuvStream = null;
+        FileDescriptor outputFd = null;
+        RandomAccessFile outputFile = null;
         try {
             if (DEBUG) Log.d(TAG, "started: " + config);
+            if (config.mOutputPath != null) {
+                outputFile = new RandomAccessFile(config.mOutputPath, "rws");
+                outputFile.setLength(0);
+                outputFd = outputFile.getFD();
+            } else {
+                outputFd = Os.memfd_create("temp", OsConstants.MFD_CLOEXEC);
+            }
 
             heifWriter = new HeifWriter.Builder(
-                    config.mOutputPath, width, height, config.mInputMode)
+                    outputFd, width, height, config.mInputMode)
                     .setRotation(config.mRotation)
                     .setGridEnabled(config.mUseGrid)
                     .setMaxImages(config.mMaxNumImages)
@@ -459,27 +485,27 @@
                 byte[] data = new byte[width * height * 3 / 2];
 
                 if (config.mInputPath != null) {
-                    inputStream = new FileInputStream(config.mInputPath);
+                    inputYuvStream = new FileInputStream(config.mInputPath);
                 }
 
                 if (DUMP_YUV_INPUT) {
-                    File outputFile = new File("/sdcard/input.yuv");
-                    outputFile.createNewFile();
-                    outputStream = new FileOutputStream(outputFile);
+                    File outputYuvFile = new File("/sdcard/input.yuv");
+                    outputYuvFile.createNewFile();
+                    outputYuvStream = new FileOutputStream(outputYuvFile);
                 }
 
                 for (int i = 0; i < actualNumImages; i++) {
                     if (DEBUG) Log.d(TAG, "fillYuvBuffer: " + i);
-                    fillYuvBuffer(i, data, width, height, inputStream);
+                    fillYuvBuffer(i, data, width, height, inputYuvStream);
                     if (DUMP_YUV_INPUT) {
                         Log.d(TAG, "@@@ dumping input YUV");
-                        outputStream.write(data);
+                        outputYuvStream.write(data);
                     }
                     heifWriter.addYuvBuffer(ImageFormat.YUV_420_888, data);
                 }
             } else if (config.mInputMode == INPUT_MODE_SURFACE) {
                 // The input surface is a surface texture using single buffer mode, draws will be
-                // blocked until onFrameAvailable is done with the buffer, which is dependant on
+                // blocked until onFrameAvailable is done with the buffer, which is dependent on
                 // how fast MediaCodec processes them, which is further dependent on how fast the
                 // MediaCodec callbacks are handled. We can't put draws on the same looper that
                 // handles MediaCodec callback, it will cause deadlock.
@@ -508,19 +534,25 @@
                 expectedPrimary = 0;
                 expectedImageCount = actualNumImages;
             }
-            verifyResult(config.mOutputPath, width, height, config.mRotation,
+            verifyResult(outputFd, width, height, config.mRotation,
                     expectedImageCount, expectedPrimary, config.mUseGrid,
                     config.mInputMode == INPUT_MODE_SURFACE);
             if (DEBUG) Log.d(TAG, "finished: PASS");
         } finally {
             try {
-                if (outputStream != null) {
-                    outputStream.close();
+                if (outputYuvStream != null) {
+                    outputYuvStream.close();
                 }
-                if (inputStream != null) {
-                    inputStream.close();
+                if (inputYuvStream != null) {
+                    inputYuvStream.close();
                 }
-            } catch (IOException e) {}
+                if (outputFile != null) {
+                    outputFile.close();
+                }
+                if (outputFd != null) {
+                    Os.close(outputFd);
+                }
+            } catch (IOException|ErrnoException e) {}
 
             if (heifWriter != null) {
                 heifWriter.close();
@@ -608,14 +640,14 @@
     }
 
     private void verifyResult(
-            String filename, int width, int height, int rotation,
+            FileDescriptor fd, int width, int height, int rotation,
             int imageCount, int primary, boolean useGrid, boolean checkColor)
             throws Exception {
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
-        retriever.setDataSource(filename);
+        retriever.setDataSource(fd);
         String hasImage = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
         if (!"yes".equals(hasImage)) {
-            throw new Exception("No images found in file " + filename);
+            throw new Exception("No images found in file descriptor");
         }
         assertEquals("Wrong width", width,
                 Integer.parseInt(retriever.extractMetadata(
@@ -636,7 +668,7 @@
 
         if (useGrid) {
             MediaExtractor extractor = new MediaExtractor();
-            extractor.setDataSource(filename);
+            extractor.setDataSource(fd);
             MediaFormat format = extractor.getTrackFormat(0);
             int tileWidth = format.getInteger(MediaFormat.KEY_TILE_WIDTH);
             int tileHeight = format.getInteger(MediaFormat.KEY_TILE_HEIGHT);
@@ -650,7 +682,8 @@
         }
 
         if (checkColor) {
-            Bitmap bitmap = BitmapFactory.decodeFile(filename);
+            Os.lseek(fd, 0, OsConstants.SEEK_SET);
+            Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd);
 
             for (int i = 0; i < COLOR_BARS.length; i++) {
                 Rect r = getColorBarRect(i, width, height);
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index d6beefe..1dfdda4 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -19,6 +19,7 @@
 import static android.media.session.PlaybackState.STATE_PLAYING;
 
 import android.content.Intent;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Rating;
 import android.media.VolumeProvider;
@@ -128,6 +129,15 @@
         assertEquals(EXTRAS_VALUE, sessionInfo.getString(EXTRAS_KEY));
     }
 
+    public void testGetTag() {
+        try {
+            String tag = mController.getTag();
+            fail();
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
     public void testSendCommand() throws Exception {
         synchronized (mWaitLock) {
             mCallback.reset();
@@ -401,25 +411,6 @@
         }
     }
 
-    /*
-    public void testPlaybackInfo() {
-        final int playbackType = MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
-        final int volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
-        final int maxVolume = 10;
-        final int currentVolume = 3;
-
-        AudioAttributes audioAttributes = new AudioAttributes.Builder().build();
-        MediaController.PlaybackInfo info = new MediaController.PlaybackInfo(
-                playbackType, audioAttributes, volumeControl, maxVolume, currentVolume);
-
-        assertEquals(playbackType, info.getPlaybackType());
-        assertEquals(audioAttributes, info.getAudioAttributes());
-        assertEquals(volumeControl, info.getVolumeControl());
-        assertEquals(maxVolume, info.getMaxVolume());
-        assertEquals(currentVolume, info.getCurrentVolume());
-    }
-    */
-
     private class MediaSessionCallback extends MediaSession.Callback {
         private long mSeekPosition;
         private long mQueueItemId;
diff --git a/tests/tests/media/src/android/media/cts/MediaDrmTest.java b/tests/tests/media/src/android/media/cts/MediaDrmTest.java
new file mode 100644
index 0000000..adc927e
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaDrmTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.media.MediaDrm;
+import android.util.Log;
+import androidx.test.runner.AndroidJUnit4;
+import java.util.List;
+import java.util.UUID;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertTrue;
+import static org.testng.Assert.assertThrows;
+
+@NonMediaMainlineTest
+@RunWith(AndroidJUnit4.class)
+public class MediaDrmTest {
+
+    private final String TAG = this.getClass().getName();
+
+    private void testSingleScheme(UUID scheme) throws Exception {
+        MediaDrm md = new MediaDrm(scheme);
+        assertTrue(md.getOpenSessionCount() <= md.getMaxSessionCount());
+        assertThrows(() -> {
+            md.closeSession(null);
+        });
+        md.close();
+    }
+
+    @Test
+    public void testSupportedCryptoSchemes() throws Exception {
+        List<UUID> supportedCryptoSchemes = MediaDrm.getSupportedCryptoSchemes();
+        if (supportedCryptoSchemes.isEmpty()) {
+            Log.w(TAG, "No supported crypto schemes reported");
+        }
+        for (UUID scheme : supportedCryptoSchemes) {
+            Log.d(TAG, "supported scheme: " + scheme.toString());
+            assertTrue(MediaDrm.isCryptoSchemeSupported(scheme));
+            testSingleScheme(scheme);
+        }
+    }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 707ff52..21149c6 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -27,6 +27,7 @@
 import android.media.MediaDataSource;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
+import static android.media.MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION;
 import android.media.cts.R;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.AppModeFull;
@@ -36,6 +37,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.BufferedReader;
 import java.io.Closeable;
 import java.io.IOException;
@@ -50,6 +53,7 @@
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+
 public class MediaExtractorTest extends AndroidTestCase {
     private static final String TAG = "MediaExtractorTest";
 
@@ -135,24 +139,46 @@
     public void testDolbyVisionMediaExtractorProfileDvheDtr() throws Exception {
         TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_30fps_dvhe_04);
 
-        assertEquals(2, mExtractor.getTrackCount());
+        assertTrue("There should be either 1 or 2 tracks",
+            0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
 
-        // First track should be a track with dolby-vision mime
         MediaFormat trackFormat = mExtractor.getTrackFormat(0);
-        String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+        int trackCountForDolbyVision = 1;
 
-        assertEquals("video/dolby-vision", mimeType);
+        // Handle the case where there is a Dolby Vision extractor
+        // Note that it may or may not have a Dolby Vision Decoder
+        if (mExtractor.getTrackCount() == 2) {
+            if (trackFormat.getString(MediaFormat.KEY_MIME)
+                    .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+                trackFormat = mExtractor.getTrackFormat(1);
+                trackCountForDolbyVision = 0;
+            }
+        }
 
-        int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);;
-        int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);;
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
 
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheDtr, profile);
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd30, level);
+            MediaFormat trackFormatForDolbyVision =
+                mExtractor.getTrackFormat(trackCountForDolbyVision);
 
-        // The second track should be with the mime video/hevc for backward compatibility
-        trackFormat = mExtractor.getTrackFormat(1);
-        mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
 
+            int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheDtr, profile);
+
+            int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd30, level);
+
+            final int trackIdForDolbyVision =
+                trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+            final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+            assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+        }
+
+        // The backward-compatible track should have mime video/hevc
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
         assertEquals("video/hevc", mimeType);
     }
 
@@ -160,43 +186,68 @@
     public void testDolbyVisionMediaExtractorProfileDvheStn() throws Exception {
         TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvhe_05);
 
-        assertEquals(1, mExtractor.getTrackCount());
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            // DvheStn exposes only a single non-backward compatible Dolby Vision HDR track.
+            assertEquals("There must be 1 track", 1, mExtractor.getTrackCount());
+            final MediaFormat trackFormat = mExtractor.getTrackFormat(0);
 
-        // DvheStn exposes only a single non-backward compatible Dolby Vision HDR track.
-        MediaFormat trackFormat = mExtractor.getTrackFormat(0);
-        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
 
-        assertEquals("video/dolby-vision", mimeType);
+            final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn, profile);
 
-        final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);;
-        final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);;
-
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn, profile);
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+            final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+        } else {
+            MediaUtils.skipTest("Device does not provide a Dolby Vision decoder");
+        }
     }
 
     // DolbyVisionMediaExtractor for profile-level (DvheSt/Fhd60).
     public void testDolbyVisionMediaExtractorProfileDvheSt() throws Exception {
         TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvhe_08);
 
-        assertEquals(2, mExtractor.getTrackCount());
+        assertTrue("There should be either 1 or 2 tracks",
+            0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
 
-        // First track should be a track with dolby-vision mime
         MediaFormat trackFormat = mExtractor.getTrackFormat(0);
-        String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+        int trackCountForDolbyVision = 1;
 
-        assertEquals("video/dolby-vision", mimeType);
+        // Handle the case where there is a Dolby Vision extractor
+        // Note that it may or may not have a Dolby Vision Decoder
+        if (mExtractor.getTrackCount() == 2) {
+            if (trackFormat.getString(MediaFormat.KEY_MIME)
+                    .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+                trackFormat = mExtractor.getTrackFormat(1);
+                trackCountForDolbyVision = 0;
+            }
+        }
 
-        final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);;
-        final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);;
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
 
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt, profile);
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+            MediaFormat trackFormatForDolbyVision =
+                mExtractor.getTrackFormat(trackCountForDolbyVision);
 
-        // The second track should be with the mime video/hevc for backward compatibility
-        trackFormat = mExtractor.getTrackFormat(1);
-        mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
 
+            int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt, profile);
+
+            int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+
+            final int trackIdForDolbyVision =
+                trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+            final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+            assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+        }
+
+        // The backward-compatible track should have mime video/hevc
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
         assertEquals("video/hevc", mimeType);
     }
 
@@ -204,69 +255,118 @@
     public void testDolbyVisionMediaExtractorProfileDvavSe() throws Exception {
         TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvav_09);
 
-        assertEquals(2, mExtractor.getTrackCount());
+        assertTrue("There should be either 1 or 2 tracks",
+            0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
 
-        // First track should be a track with dolby-vision mime
         MediaFormat trackFormat = mExtractor.getTrackFormat(0);
-        String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+        int trackCountForDolbyVision = 1;
 
-        assertEquals("video/dolby-vision", mimeType);
+        // Handle the case where there is a Dolby Vision extractor
+        // Note that it may or may not have a Dolby Vision Decoder
+        if (mExtractor.getTrackCount() == 2) {
+            if (trackFormat.getString(MediaFormat.KEY_MIME)
+                    .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+                trackFormat = mExtractor.getTrackFormat(1);
+                trackCountForDolbyVision = 0;
+            }
+        }
 
-        final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);;
-        final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);;
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
 
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvavSe, profile);
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+            MediaFormat trackFormatForDolbyVision =
+                mExtractor.getTrackFormat(trackCountForDolbyVision);
 
-        // The second track should be with the mime video/hevc for backward compatibility
-        trackFormat = mExtractor.getTrackFormat(1);
-        mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
 
+            int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvavSe, profile);
+
+            int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+
+            final int trackIdForDolbyVision =
+                trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+            final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+            assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+        }
+
+        // The backward-compatible track should have mime video/avc
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
         assertEquals("video/avc", mimeType);
-
     }
 
     // DolbyVisionMediaExtractor for profile-level (Dvav1 10.0/Uhd30)
+    @SmallTest
     public void testDolbyVisionMediaExtractorProfileDvav1() throws Exception {
         TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_3840x2160_30fps_dav1_10);
 
-        assertEquals(1, mExtractor.getTrackCount());
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals(1, mExtractor.getTrackCount());
 
-        // Dvav1 10 exposes a single backward compatible track.
-        MediaFormat trackFormat = mExtractor.getTrackFormat(0);
-        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            // Dvav1 10 exposes a single backward compatible track.
+            final MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+            final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
 
-        assertEquals("video/dolby-vision", mimeType);
+            assertEquals("video/dolby-vision", mimeType);
 
-        final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);;
-        final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);;
+            final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);
+            final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);
 
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvav110, profile);
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd30, level);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvav110, profile);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd30, level);
+        } else {
+            MediaUtils.skipTest("Device does not provide a Dolby Vision decoder");
+        }
     }
 
     // DolbyVisionMediaExtractor for profile-level (Dvav1 10.1/Uhd30)
+    @SmallTest
     public void testDolbyVisionMediaExtractorProfileDvav1_2() throws Exception {
         TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_3840x2160_30fps_dav1_10_2);
 
-        assertEquals(2, mExtractor.getTrackCount());
+        assertTrue("There should be either 1 or 2 tracks",
+            0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
 
-        // First track should be a track with dolby-vision mime
         MediaFormat trackFormat = mExtractor.getTrackFormat(0);
-        String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+        int trackCountForDolbyVision = 1;
 
-        assertEquals("video/dolby-vision", mimeType);
+        // Handle the case where there is a Dolby Vision extractor
+        // Note that it may or may not have a Dolby Vision Decoder
+        if (mExtractor.getTrackCount() == 2) {
+            if (trackFormat.getString(MediaFormat.KEY_MIME)
+                    .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+                trackFormat = mExtractor.getTrackFormat(1);
+                trackCountForDolbyVision = 0;
+            }
+        }
 
-        final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);;
-        final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);;
+        if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+            assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
 
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvav110, profile);
-        assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd30, level);
+            MediaFormat trackFormatForDolbyVision =
+                mExtractor.getTrackFormat(trackCountForDolbyVision);
 
-        // The second track should be with the mime video/av01 for backward compatibility
-        trackFormat = mExtractor.getTrackFormat(1);
-        mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+            final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+            assertEquals("video/dolby-vision", mimeType);
 
+            int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvav110, profile);
+
+            int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+            assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd30, level);
+
+            final int trackIdForDolbyVision =
+                trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+            final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+            assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+        }
+
+        // The backward-compatible track should have mime video/av01
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
         assertEquals("video/av01", mimeType);
     }
 
diff --git a/tests/tests/media/src/android/media/cts/MediaMetricsTest.java b/tests/tests/media/src/android/media/cts/MediaMetricsTest.java
new file mode 100644
index 0000000..7898b2d
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaMetricsTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.media.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.media.MediaMetrics;
+import android.os.Bundle;
+import android.os.Process;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for MediaMetrics item handling.
+ */
+
+@NonMediaMainlineTest
+@RunWith(AndroidJUnit4.class)
+public class MediaMetricsTest {
+
+    /**
+     * This tests MediaMetrics item creation.
+     */
+    @Test
+    public void testBasicItem() {
+        final String key = "Key";
+        final MediaMetrics.Item item = new MediaMetrics.Item(key);
+
+        item.putInt("int", (int) 1)
+            .putLong("long", (long) 2)
+            .putString("string", "ABCD")
+            .putDouble("double", (double) 3.1);
+
+        // Verify what is in the item by converting to a bundle.
+        // This uses special MediaMetrics.Item APIs for CTS test.
+        // The BUNDLE_* string keys represent internal Item data to be verified.
+        final Bundle bundle = item.toBundle();
+
+        assertEquals(1, bundle.getInt("int"));
+        assertEquals(2, bundle.getLong("long"));
+        assertEquals("ABCD", bundle.getString("string"));
+        assertEquals(3.1, bundle.getDouble("double"), 1e-6 /* delta */);
+
+        assertEquals("Key", bundle.getString(MediaMetrics.Item.BUNDLE_KEY));
+        assertEquals(-1, bundle.getInt(MediaMetrics.Item.BUNDLE_PID));  // default PID
+        assertEquals(-1, bundle.getInt(MediaMetrics.Item.BUNDLE_UID));  // default UID
+        assertEquals(0, bundle.getChar(MediaMetrics.Item.BUNDLE_VERSION));
+        assertEquals(key.length() + 1, bundle.getChar(MediaMetrics.Item.BUNDLE_KEY_SIZE));
+        assertEquals(0, bundle.getLong(MediaMetrics.Item.BUNDLE_TIMESTAMP)); // default Time
+        assertEquals(4, bundle.getInt(MediaMetrics.Item.BUNDLE_PROPERTY_COUNT));
+    }
+
+    /**
+     * This tests MediaMetrics item buffer expansion when the initial buffer capacity is set to 1.
+     */
+    @Test
+    public void testBigItem() {
+        final String key = "Key";
+        final int intKeyCount = 10000;
+        final MediaMetrics.Item item = new MediaMetrics.Item(
+                key, 1 /* pid */, 2 /* uid */, 3 /* time */, 1 /* capacity */);
+
+        item.putInt("int", (int) 1)
+            .putLong("long", (long) 2)
+            .putString("string", "ABCD")
+            .putDouble("double", (double) 3.1);
+
+        // Putting 10000 int properties forces the item to reallocate the buffer several times.
+        for (Integer i = 0; i < intKeyCount; ++i) {
+            item.putInt(i.toString(), i);
+        }
+
+        // Verify what is in the item by converting to a bundle.
+        // This uses special MediaMetrics.Item APIs for CTS test.
+        // The BUNDLE_* string keys represent internal Item data to be verified.
+        final Bundle bundle = item.toBundle();
+
+        assertEquals(1, bundle.getInt("int"));
+        assertEquals(2, bundle.getLong("long"));
+        assertEquals("ABCD", bundle.getString("string"));
+        assertEquals(3.1, bundle.getDouble("double"), 1e-6 /* delta */);
+
+        assertEquals(key, bundle.getString(MediaMetrics.Item.BUNDLE_KEY));
+        assertEquals(1, bundle.getInt(MediaMetrics.Item.BUNDLE_PID));
+        assertEquals(2, bundle.getInt(MediaMetrics.Item.BUNDLE_UID));
+        assertEquals(0, bundle.getChar(MediaMetrics.Item.BUNDLE_VERSION));
+        assertEquals(key.length() + 1, bundle.getChar(MediaMetrics.Item.BUNDLE_KEY_SIZE));
+        assertEquals(3, bundle.getLong(MediaMetrics.Item.BUNDLE_TIMESTAMP));
+
+        for (Integer i = 0; i < intKeyCount; ++i) {
+            assertEquals((int) i, bundle.getInt(i.toString()));
+        }
+
+        assertEquals(intKeyCount + 4, bundle.getInt(MediaMetrics.Item.BUNDLE_PROPERTY_COUNT));
+
+        item.clear(); // removes properties.
+        item.putInt("value", (int) 100);
+
+        final Bundle bundle2 = item.toBundle();
+
+        assertEquals(key, bundle2.getString(MediaMetrics.Item.BUNDLE_KEY));
+        assertEquals(1, bundle2.getInt(MediaMetrics.Item.BUNDLE_PID));
+        assertEquals(2, bundle2.getInt(MediaMetrics.Item.BUNDLE_UID));
+        assertEquals(0, bundle2.getChar(MediaMetrics.Item.BUNDLE_VERSION));
+        assertEquals(key.length() + 1, bundle2.getChar(MediaMetrics.Item.BUNDLE_KEY_SIZE));
+        assertEquals(0, bundle2.getLong(MediaMetrics.Item.BUNDLE_TIMESTAMP)); // time is reset.
+
+        for (Integer i = 0; i < intKeyCount; ++i) {
+            assertEquals(-1, bundle2.getInt(i.toString(), -1));
+        }
+        assertEquals(100, bundle2.getInt("value"));
+        assertEquals(1, bundle2.getInt(MediaMetrics.Item.BUNDLE_PROPERTY_COUNT));
+
+        // Now override pid, uid, and time.
+        item.setPid(10)
+            .setUid(11)
+            .setTimestamp(12);
+        final Bundle bundle3 = item.toBundle();
+        assertEquals(10, bundle3.getInt(MediaMetrics.Item.BUNDLE_PID));
+        assertEquals(11, bundle3.getInt(MediaMetrics.Item.BUNDLE_UID));
+        assertEquals(12, bundle3.getLong(MediaMetrics.Item.BUNDLE_TIMESTAMP));
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index 4f27289..8cb6f3d 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -618,14 +618,14 @@
 
     public static void startMediaScan() {
         new Thread(() -> {
-            MediaStore.scanVolume(InstrumentationRegistry.getTargetContext(),
-                    Environment.getExternalStorageDirectory());
+            MediaStore.scanVolume(InstrumentationRegistry.getTargetContext().getContentResolver(),
+                    MediaStore.VOLUME_EXTERNAL_PRIMARY);
         }).start();
     }
 
     public static void startMediaScanAndWait() {
-        MediaStore.scanVolume(InstrumentationRegistry.getTargetContext(),
-                Environment.getExternalStorageDirectory());
+        MediaStore.scanVolume(InstrumentationRegistry.getTargetContext().getContentResolver(),
+                MediaStore.VOLUME_EXTERNAL_PRIMARY);
     }
 
     private void checkMediaScannerConnection() {
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity2.java b/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity2.java
index 79d0d2d..ea0567f 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity2.java
+++ b/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity2.java
@@ -22,11 +22,11 @@
 
 public class ResourceManagerTestActivity2 extends ResourceManagerTestActivityBase {
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onResume() {
         TAG = "ResourceManagerTestActivity2";
 
-        Log.d(TAG, "onCreate called.");
-        super.onCreate(savedInstanceState);
+        Log.d(TAG, "onResume called.");
+        super.onResume();
 
         int result = (allocateCodecs(1 /* max */) == 1) ? RESULT_OK : RESULT_CANCELED;
         finishWithResult(result);
diff --git a/tests/tests/net/src/android/net/cts/MacAddressTest.java b/tests/tests/net/src/android/net/cts/MacAddressTest.java
index af1e760..4d25e62 100644
--- a/tests/tests/net/src/android/net/cts/MacAddressTest.java
+++ b/tests/tests/net/src/android/net/cts/MacAddressTest.java
@@ -20,6 +20,11 @@
 import static android.net.MacAddress.TYPE_MULTICAST;
 import static android.net.MacAddress.TYPE_UNICAST;
 
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.net.MacAddress;
@@ -30,6 +35,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.net.Inet6Address;
 import java.util.Arrays;
 
 @SmallTest
@@ -161,4 +167,57 @@
         } catch (NullPointerException excepted) {
         }
     }
+
+    @Test
+    public void testMatches() {
+        // match 4 bytes prefix
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:00:00"),
+                MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+        // match bytes 0,1,2 and 5
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:00:00:11"),
+                MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+        // match 34 bit prefix
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+                MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+        // fail to match 36 bit prefix
+        assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:40:00"),
+                MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+        // match all 6 bytes
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+                MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+        // match none of 6 bytes
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("00:00:00:00:00:00"),
+                MacAddress.fromString("00:00:00:00:00:00")));
+    }
+
+    /**
+     * Tests that link-local address generation from MAC is valid.
+     */
+    @Test
+    public void testLinkLocalFromMacGeneration() {
+        final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+        final byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+                0x74, (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
+        final Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
+        assertTrue(llv6.isLinkLocalAddress());
+        assertArrayEquals(inet6ll, llv6.getAddress());
+    }
+
+    @Test
+    public void testParcelMacAddress() {
+        final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+
+        assertParcelSane(mac, 1);
+    }
 }
diff --git a/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java
index 639db8a..e93d573 100644
--- a/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java
+++ b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java
@@ -22,41 +22,41 @@
 import android.test.AndroidTestCase;
 
 public class WifiP2pConfigTest extends AndroidTestCase {
-    static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello";
-    static final String TEST_PASSPHRASE = "8etterW0r1d";
-    static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ;
-    static final int TEST_OWNER_FREQ = 2447;
-    static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff";
+    private static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello";
+    private static final String TEST_PASSPHRASE = "8etterW0r1d";
+    private static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ;
+    private static final int TEST_OWNER_FREQ = 2447;
+    private static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff";
 
     public void testWifiP2pConfigBuilderForPersist() {
-        WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder();
-        builder.setNetworkName(TEST_NETWORK_NAME)
+        WifiP2pConfig config = new WifiP2pConfig.Builder()
+                .setNetworkName(TEST_NETWORK_NAME)
                 .setPassphrase(TEST_PASSPHRASE)
                 .setGroupOperatingBand(TEST_OWNER_BAND)
                 .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS))
-                .enablePersistentMode(true);
-        WifiP2pConfig config = builder.build();
+                .enablePersistentMode(true)
+                .build();
 
-        assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS));
-        assertTrue(config.networkName.equals(TEST_NETWORK_NAME));
-        assertTrue(config.passphrase.equals(TEST_PASSPHRASE));
-        assertEquals(config.groupOwnerBand, TEST_OWNER_BAND);
-        assertEquals(config.netId, WifiP2pGroup.PERSISTENT_NET_ID);
+        assertEquals(config.deviceAddress, TEST_DEVICE_ADDRESS);
+        assertEquals(config.getNetworkName(), TEST_NETWORK_NAME);
+        assertEquals(config.getPassphrase(), TEST_PASSPHRASE);
+        assertEquals(config.getGroupOwnerBand(), TEST_OWNER_BAND);
+        assertEquals(config.getNetworkId(), WifiP2pGroup.PERSISTENT_NET_ID);
     }
 
     public void testWifiP2pConfigBuilderForNonPersist() {
-        WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder();
-        builder.setNetworkName(TEST_NETWORK_NAME)
+        WifiP2pConfig config = new WifiP2pConfig.Builder()
+                .setNetworkName(TEST_NETWORK_NAME)
                 .setPassphrase(TEST_PASSPHRASE)
                 .setGroupOperatingFrequency(TEST_OWNER_FREQ)
                 .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS))
-                .enablePersistentMode(false);
-        WifiP2pConfig config = builder.build();
+                .enablePersistentMode(false)
+                .build();
 
-        assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS));
-        assertTrue(config.networkName.equals(TEST_NETWORK_NAME));
-        assertTrue(config.passphrase.equals(TEST_PASSPHRASE));
-        assertEquals(config.groupOwnerBand, TEST_OWNER_FREQ);
-        assertEquals(config.netId, WifiP2pGroup.TEMPORARY_NET_ID);
+        assertEquals(config.deviceAddress, TEST_DEVICE_ADDRESS);
+        assertEquals(config.getNetworkName(), TEST_NETWORK_NAME);
+        assertEquals(config.getPassphrase(), TEST_PASSPHRASE);
+        assertEquals(config.getGroupOwnerBand(), TEST_OWNER_FREQ);
+        assertEquals(config.getNetworkId(), WifiP2pGroup.TEMPORARY_NET_ID);
     }
 }
diff --git a/tests/tests/os/src/android/os/storage/cts/CrateInfoTest.java b/tests/tests/os/src/android/os/storage/cts/CrateInfoTest.java
new file mode 100644
index 0000000..8c78d87
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/CrateInfoTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Process;
+import android.os.storage.CrateInfo;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CrateInfoTest {
+    @Rule
+    public TestName mTestName = new TestName();
+
+    @Test
+    public void getLabel_shouldMatchTheConstructor() {
+        CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName());
+
+        assertThat(crateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+    }
+
+    @Test
+    public void newCrateInfo_withNormalLabel_shouldBeSuccess() {
+        CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName());
+
+        assertThat(crateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+    }
+
+    @Test
+    public void newCrateInfo_withNormalLabelAndExpiration_shouldBeSuccess() {
+        CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName(), 0);
+
+        assertThat(crateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+    }
+
+    @Test
+    public void newCrateInfo_withNormalLabelAndMaxExpiration_shouldBeSuccess() {
+        CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName(), Long.MAX_VALUE);
+
+        assertThat(crateInfo.getExpirationMillis()).isEqualTo(Long.MAX_VALUE);
+    }
+
+    @Test
+    public void newCrateInfo_nullLabel_throwIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+        try {
+            new CrateInfo(null);
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void newCrateInfo_emptyString_throwIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+        try {
+            new CrateInfo("");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void newCrateInfo_withNegativeExpiration_throwIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+        try {
+            new CrateInfo(mTestName.getMethodName(), -1);
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void readFromParcel_shouldMatchFromWriteToParcel() {
+        Parcel parcel = Parcel.obtain();
+        CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName(), Long.MAX_VALUE);
+        crateInfo.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        CrateInfo readFromCrateInfo = CrateInfo.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+
+        assertThat(readFromCrateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+        assertThat(readFromCrateInfo.getExpirationMillis()).isEqualTo(Long.MAX_VALUE);
+    }
+
+    @Test
+    public void copyFrom_validatedCrate_shouldReturnNonNull() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        CrateInfo crateInfo = CrateInfo.copyFrom(Process.myUid(), context.getOpPackageName(),
+                mTestName.getMethodName());
+
+        assertThat(crateInfo).isNotNull();
+    }
+
+    @Test
+    public void copyFrom_invalidCrate_shouldReturnNull() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        CrateInfo crateInfo = CrateInfo.copyFrom(Process.myUid(), context.getOpPackageName(),
+                null);
+
+        assertThat(crateInfo).isNull();
+    }
+
+    @Test
+    public void copyFrom_invalidPackageName_shouldReturnNull() {
+        CrateInfo crateInfo = CrateInfo.copyFrom(Process.myUid(), null,
+                mTestName.getMethodName());
+
+        assertThat(crateInfo).isNull();
+    }
+}
diff --git a/tests/tests/os/src/android/os/storage/cts/OWNERS b/tests/tests/os/src/android/os/storage/cts/OWNERS
new file mode 100644
index 0000000..948bcad
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 141660526
+per-file CrateInfoTest.java = felkachang@google.com
+per-file StorageCrateTest.java = felkachang@google.com
+per-file StorageStatsManagerTest.java = felkachang@google.com
+
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageCrateTest.java b/tests/tests/os/src/android/os/storage/cts/StorageCrateTest.java
new file mode 100644
index 0000000..99ea30c
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/StorageCrateTest.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageCrateTest {
+    private static final String CRATES_ROOT = "crates";
+    @Rule
+    public TestName mTestName = new TestName();
+
+    private Context mContext;
+    private Path mCratesRoot;
+    private String mCrateId;
+    private Path mCratePath;
+
+    private void cleanAllOfCrates() throws IOException {
+        if (!mCratesRoot.toFile().exists()) {
+            return;
+        }
+
+        Files.walkFileTree(mCratesRoot, new SimpleFileVisitor<>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                    throws IOException {
+                Files.deleteIfExists(file);
+                return super.visitFile(file, attrs);
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                    throws IOException {
+                Files.deleteIfExists(dir);
+                return super.postVisitDirectory(dir, exc);
+            }
+        });
+
+        Files.deleteIfExists(mCratesRoot);
+    }
+
+    /**
+     * Setup the necessary member field used by test methods.
+     * <p>It needs to remove all of directories in {@link Context#getCrateDir(String crateId)} that
+     * include {@link Context#getCrateDir(String crateId)} itself.
+     * Why it needs to run cleanAllOfCrates, the process may crashed before tearDown. Running
+     * cleanAllOfCrates to make sure the test environment is clean.</p>
+     */
+    @Before
+    public void setUp() throws IOException {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mCratesRoot = mContext.getDataDir().toPath().resolve(CRATES_ROOT);
+        mCrateId = mTestName.getMethodName();
+        mCratePath = mCratesRoot.resolve(mTestName.getMethodName());
+
+        cleanAllOfCrates();
+    }
+
+    @Test
+    public void getCrateDir_notInvoke_cratesRootShouldNotExist() {
+        final File cratesRootDir = mCratesRoot.toFile();
+
+        assertThat(cratesRootDir.exists()).isFalse();
+    }
+
+    @Test
+    public void getCrateDir_withCrateId_cratesRootExist() {
+        final File cratesRootDir = mCratesRoot.toFile();
+
+        mContext.getCrateDir(mCrateId);
+
+        assertThat(cratesRootDir.exists()).isTrue();
+    }
+
+    @Test
+    public void getCrateDir_withCrateId_shouldReturnNonNullDir() {
+        final File crateDir = mContext.getCrateDir(mCrateId);
+
+        assertThat(crateDir).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_withCrateId_cratePathBeDirectory() {
+        final File crateDir = mContext.getCrateDir(mCrateId);
+
+        assertThat(crateDir.isDirectory()).isTrue();
+    }
+
+    @Test
+    public void getCrateDir_withCrateId_cratePathShouldExist() {
+        final File crateDir = mContext.getCrateDir(mCrateId);
+
+        assertThat(crateDir.exists()).isTrue();
+    }
+
+    @Test
+    public void getCrateDir_withCrateId_cratesRootShouldUnderDataDir() {
+        final File cratesRootDir = mCratesRoot.toFile();
+
+        mContext.getCrateDir(mCrateId);
+
+        assertThat(cratesRootDir.getParentFile().getName())
+                .isEqualTo(mContext.getDataDir().getName());
+    }
+
+    @Test
+    public void getCrateDir_withCrateId_crateDirShouldUnderCratesRootDir() {
+        final File cratesRootDir = mCratesRoot.toFile();
+        final File crateDir = mCratePath.toFile();
+
+        mContext.getCrateDir(mCrateId);
+
+        assertThat(crateDir.getParentFile().getName()).isEqualTo(cratesRootDir.getName());
+    }
+
+    @Test
+    public void getCrateDir_anyExceptionHappened_shouldNotCreateAnyDir() {
+        File crateDir = null;
+
+        try {
+            crateDir = mContext.getCrateDir(null);
+        } catch (Exception e) {
+        }
+
+        assertThat(crateDir).isNull();
+    }
+
+    @Test
+    public void getCrateDir_nullCrateId_crateDirShouldUnderCratesRootDir() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir(null);
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_emptyCrateId_crateDirShouldUnderCratesRootDir() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdIsDot_crateDirShouldUnderCratesRootDir() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir(".");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdIsDotDot_crateDirShouldUnderCratesRootDir() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("..");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdPrefixContainsDotDot_shouldTriggerIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("../etc/password");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdContainsDotDot_shouldTriggerIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("normalCrate/../../../etc/password");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdSuffixContainsDotDot_shouldTriggerIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("normalCrate/etc/password/../../..");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdStartWithSlashSlash_shouldTriggerIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("/etc/password");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdStartWithSlash_shouldTriggerIllegalArgumentException() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("//etc/password");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_crateIdContainsSlashChar_shouldBeInvalidated() {
+        IllegalArgumentException illegalArgumentException = null;
+
+        try {
+            mContext.getCrateDir("A/B");
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_superLongCrateId_shouldBeIllegalArgument() throws IOException {
+        IllegalArgumentException illegalArgumentException = null;
+        StringBuilder sb = new StringBuilder(1024);
+        while (sb.length() > 1024) {
+            sb.append(mCrateId);
+        }
+
+        try {
+            mContext.getCrateDir(sb.toString());
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_callWithDifferentCrateId_shouldGenerateTheSameNumberOfCrates() {
+        final String[] expectedCrates = new String[] {"A", "B", "C"};
+
+        for (String crateId : expectedCrates) {
+            mContext.getCrateDir(crateId);
+        }
+
+        String[] newChildDir = mCratesRoot.toFile().list();
+        assertThat(newChildDir).asList().containsAllIn(expectedCrates);
+    }
+
+    @Test
+    public void getCrateDir_withUtf8Characters_shouldCreateSuccess() {
+        String utf8Characters = "æɛəɚʊʌɔ" + "宮商角止羽" + "あいうえお"
+                + "ㅏㅓㅗㅜㅡㅣㅐㅔㅚㅟㅑㅕㅛㅠㅒㅖㅘㅙㅝㅞㅢ";
+
+        File crateDir = mContext.getCrateDir(utf8Characters);
+
+        assertThat(crateDir.getName()).isEqualTo(utf8Characters);
+    }
+
+    @Test
+    public void getCrateDir_withNullCharacter_shouldBeFail() {
+        String utf8Characters = "abcdefg\0hijklmnopqrstuvwxyz";
+
+        IllegalArgumentException illegalArgumentException = null;
+        try {
+            mContext.getCrateDir(utf8Characters);
+        } catch (IllegalArgumentException e) {
+            illegalArgumentException = e;
+        }
+
+        assertThat(illegalArgumentException).isNotNull();
+    }
+
+    @Test
+    public void getCrateDir_withLineFeedCharacter_shouldSuccess() {
+        String utf8Characters = "abcdefg\nhijklmnopqrstuvwxyz";
+
+        File crateDir = mContext.getCrateDir(utf8Characters);
+
+        assertThat(crateDir.exists() && crateDir.isDirectory()).isTrue();
+    }
+}
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java
new file mode 100644
index 0000000..9643aef
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage.cts;
+
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.app.UiAutomation;
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.storage.CrateInfo;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.truth.Correspondence;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collection;
+import java.util.UUID;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageStatsManagerTest {
+    private static final String CRATES_ROOT = "crates";
+
+    private Context mContext;
+    private StorageManager mStorageManager;
+    private StorageStatsManager mStorageStatsManager;
+
+    @Rule
+    public TestName mTestName = new TestName();
+    private Path mCratesPath;
+    private Path mCrateDirPath;
+    private UUID mUuid;
+    private String mCrateId;
+
+    private void cleanAllOfCrates() throws IOException {
+        if (!mCratesPath.toFile().exists()) {
+            return;
+        }
+
+        Files.walkFileTree(mCratesPath, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                    throws IOException {
+                Files.deleteIfExists(file);
+                return super.visitFile(file, attrs);
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                    throws IOException {
+                Files.deleteIfExists(dir);
+                return super.postVisitDirectory(dir, exc);
+            }
+        });
+        Files.deleteIfExists(mCratesPath);
+    }
+
+    /**
+     * Setup the necessary member field used by test methods.
+     */
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
+        mStorageStatsManager =
+            (StorageStatsManager) mContext.getSystemService(Context.STORAGE_STATS_SERVICE);
+
+        mCratesPath = mContext.getDataDir().toPath().resolve(CRATES_ROOT);
+        cleanAllOfCrates();
+
+        mCrateId = mTestName.getMethodName();
+
+        mCrateDirPath = mCratesPath.resolve(mCrateId);
+        mUuid = mStorageManager.getUuidForPath(mCratesPath.toFile());
+    }
+
+    /**
+     * To clean all of crated folders to prevent from flaky.
+     * @throws Exception happened when the tearDown tries to removed all of folders and files.
+     */
+    @After
+    public void tearDown() throws Exception {
+        cleanAllOfCrates();
+    }
+
+    @Test
+    public void queryCratesForUid_noCratedFolder_shouldBeEmpty() throws Exception {
+        Collection<CrateInfo> collection = mStorageStatsManager.queryCratesForUid(mUuid,
+                Process.myUid());
+
+        assertThat(collection.size()).isEqualTo(0);
+    }
+
+    private Collection<CrateInfo> queryCratesForUser(boolean byShell, UUID uuid,
+            UserHandle userHandle)
+            throws PackageManager.NameNotFoundException, IOException {
+        final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation();
+        if (byShell) {
+            uiAutomation.adoptShellPermissionIdentity(Manifest.permission.MANAGE_CRATES);
+        }
+        Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUser(uuid,
+                userHandle);
+        if (byShell) {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+        return crateInfos;
+    }
+    @Test
+    public void queryCratesForUser_noCratedFolder_shouldBeEmpty() throws Exception {
+        Collection<CrateInfo> collection = queryCratesForUser(true, mUuid,
+                Process.myUserHandle());
+
+        assertThat(collection.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void queryCratesForPackage_noCratedFolder_shouldBeEmpty() throws Exception {
+        Collection<CrateInfo> collection = mStorageStatsManager.queryCratesForPackage(mUuid,
+                mContext.getOpPackageName(), Process.myUserHandle());
+
+        assertThat(collection.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void queryCratesForUid_withOtherUid_shouldRiseSecurityIssueException() throws Exception {
+        int fakeUid = UserHandle.getUid(MIN_SECONDARY_USER_ID,
+                UserHandle.getAppId(Process.myUid()));
+        SecurityException securityException = null;
+
+        try {
+            mStorageStatsManager.queryCratesForUid(mUuid, fakeUid);
+        } catch (SecurityException e) {
+            securityException = e;
+        }
+
+        assertThat(securityException).isNotNull();
+    }
+
+    @Test
+    public void queryCratesForUser_withOtherUid_shouldRiseSecurityIssueException()
+            throws Exception {
+        UserHandle fakeUserHandle = UserHandle.of(MIN_SECONDARY_USER_ID);
+        SecurityException securityException = null;
+
+        try {
+            mStorageStatsManager.queryCratesForUser(mUuid, fakeUserHandle);
+        } catch (SecurityException e) {
+            securityException = e;
+        }
+
+        assertThat(securityException).isNotNull();
+    }
+
+    @Test
+    public void queryCratesForPackage_withOtherUid_shouldRiseSecurityIssueException()
+            throws Exception {
+        UserHandle fakeUserHandle = UserHandle.of(MIN_SECONDARY_USER_ID);
+        SecurityException securityException = null;
+
+        try {
+            mStorageStatsManager.queryCratesForPackage(mUuid,
+                    mContext.getOpPackageName(), fakeUserHandle);
+        } catch (SecurityException e) {
+            securityException = e;
+        }
+
+        assertThat(securityException).isNotNull();
+    }
+
+    @Test
+    public void queryCratesForUid_addOneDirectory_shouldIncreasingOneCrate()
+            throws Exception {
+        Collection<CrateInfo> originalCollection = mStorageStatsManager.queryCratesForUid(
+                mUuid, Process.myUid());
+
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForUid(
+                mUuid, Process.myUid());
+        assertThat(newCollection.size()).isEqualTo(originalCollection.size() + 1);
+    }
+
+    @Test
+    public void queryCratesForUser_addOneDirectory_shouldIncreasingOneCrate()
+            throws Exception {
+        Collection<CrateInfo> originalCollection = queryCratesForUser(true, mUuid,
+                Process.myUserHandle());
+
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> newCollection = queryCratesForUser(true,
+                mUuid, Process.myUserHandle());
+        assertThat(newCollection.size()).isEqualTo(originalCollection.size() + 1);
+    }
+
+    @Test
+    public void queryCratesForPackage_addOneDirectory_shouldIncreasingOneCrate()
+            throws Exception {
+        Collection<CrateInfo> originalCollection = mStorageStatsManager.queryCratesForPackage(
+                mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForPackage(
+                mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+        assertThat(newCollection.size()).isEqualTo(originalCollection.size() + 1);
+    }
+
+    @Test
+    public void queryCratesForUid_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
+            throws Exception {
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
+                mUuid, Process.myUid());
+
+        assertThat(crateInfos.iterator().next().getLabel()).isEqualTo(mTestName.getMethodName());
+    }
+
+    @Test
+    public void queryCratesForUser_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
+            throws Exception {
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> crateInfos =  queryCratesForUser(true, mUuid,
+                Process.myUserHandle());
+
+        assertThat(crateInfos.iterator().next().getLabel()).isEqualTo(mTestName.getMethodName());
+    }
+
+    @Test
+    public void queryCratesForPackage_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
+            throws Exception {
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
+                mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+        assertThat(crateInfos.iterator().next().getLabel()).isEqualTo(mTestName.getMethodName());
+    }
+
+    @Test
+    public void queryCratesForUid_withoutSetCrateInfo_expirationShouldBeZero()
+            throws Exception {
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
+                mUuid, Process.myUid());
+
+        assertThat(crateInfos.iterator().next().getExpirationMillis()).isEqualTo(0);
+    }
+
+    @Test
+    public void queryCratesForUser_withoutSetCrateInfo_expirationShouldBeZero()
+            throws Exception {
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> crateInfos =  queryCratesForUser(true, mUuid,
+                Process.myUserHandle());
+
+        assertThat(crateInfos.iterator().next().getExpirationMillis()).isEqualTo(0);
+    }
+
+    @Test
+    public void queryCratesForPackage_withoutSetCrateInfo_expirationShouldBeZero()
+            throws Exception {
+        mContext.getCrateDir(mCrateId);
+
+        Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
+                mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+        assertThat(crateInfos.iterator().next().getExpirationMillis()).isEqualTo(0);
+    }
+
+    @Test
+    public void queryCratesForUid_removeCratedDir_shouldDecreaseTheNumberOfCrates()
+            throws Exception {
+        for (int i = 0; i < 3; i++) {
+            mContext.getCrateDir(mCrateId + "_" + i);
+        }
+        Collection<CrateInfo> oldCollection = mStorageStatsManager.queryCratesForUid(mUuid,
+                Process.myUid());
+
+        Files.deleteIfExists(mContext.getCrateDir(mCrateId + "_" + 1).toPath());
+
+        Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForUid(
+                mUuid, Process.myUid());
+        assertThat(newCollection.size()).isEqualTo(oldCollection.size() - 1);
+    }
+
+    @Test
+    public void queryCratesForPackage_removeCratedDir_shouldDecreaseTheNumberOfCrates()
+            throws Exception {
+        for (int i = 0; i < 3; i++) {
+            mContext.getCrateDir(mCrateId + "_" + i);
+        }
+        Collection<CrateInfo> oldCollection = mStorageStatsManager.queryCratesForPackage(mUuid,
+                mContext.getOpPackageName(), Process.myUserHandle());
+
+        Files.deleteIfExists(mContext.getCrateDir(mCrateId + "_" + 1).toPath());
+
+        Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForPackage(mUuid,
+                mContext.getOpPackageName(), Process.myUserHandle());
+        assertThat(newCollection.size()).isEqualTo(oldCollection.size() - 1);
+    }
+
+    @Test
+    public void queryCratesForUser_removeCratedDir_shouldDecreaseTheNumberOfCrates()
+            throws Exception {
+        for (int i = 0; i < 3; i++) {
+            mContext.getCrateDir(mCrateId + "_" + i);
+        }
+        Collection<CrateInfo> oldCollection = queryCratesForUser(true, mUuid,
+                Process.myUserHandle());
+
+        Files.deleteIfExists(mContext.getCrateDir(mCrateId + "_" + 1).toPath());
+
+        Collection<CrateInfo> newCollection = queryCratesForUser(true, mUuid,
+                Process.myUserHandle());
+        assertThat(newCollection.size()).isEqualTo(oldCollection.size() - 1);
+    }
+
+    Correspondence<CrateInfo, String> mCorrespondenceByLabel = new Correspondence<>() {
+        @Override
+        public boolean compare(CrateInfo crateInfo, String expect) {
+            return TextUtils.equals(crateInfo.getLabel(), expect);
+        }
+
+        @Override
+        public String toString() {
+            return "It should be the crated folder name";
+        }
+    };
+
+    @Test
+    public void queryCratesForUid_createDeepPath_shouldCreateOneCrate()
+            throws Exception {
+        final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
+        Files.createDirectories(threeLevelPath);
+
+        Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
+                mUuid, Process.myUid());
+
+        assertThat(crateInfos).comparingElementsUsing(mCorrespondenceByLabel)
+                .containsExactly(mCrateId);
+    }
+
+    @Test
+    public void queryCratesForUser_createDeepPath_shouldCreateOneCrate()
+            throws Exception {
+        final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
+        Files.createDirectories(threeLevelPath);
+
+        Collection<CrateInfo> crateInfos = queryCratesForUser(true, mUuid,
+                Process.myUserHandle());
+
+        assertThat(crateInfos).comparingElementsUsing(mCorrespondenceByLabel)
+                .containsExactly(mCrateId);
+    }
+
+    @Test
+    public void queryCratesForPackage_createDeepPath_shouldCreateOneCrate()
+            throws Exception {
+        final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
+        Files.createDirectories(threeLevelPath);
+
+        Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
+                mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+        assertThat(crateInfos).comparingElementsUsing(mCorrespondenceByLabel)
+                .containsExactly(mCrateId);
+    }
+}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index d9e2ded..cf6bbe7 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -1778,6 +1778,13 @@
         android:description="@string/permdesc_vibrate"
         android:protectionLevel="normal|instant" />
 
+    <!-- Allows access to the vibrator always-on settings.
+         <p>Protection level: signature
+         @hide
+    -->
+    <permission android:name="android.permission.VIBRATE_ALWAYS_ON"
+        android:protectionLevel="signature" />
+
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
          from dimming.
          <p>Protection level: normal
@@ -2129,6 +2136,14 @@
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
         android:protectionLevel="signature|documenter" />
 
+    <!-- Allows an application to manage access to crates, usually as part
+         of a crates picker.
+         @hide
+         @TestApi
+    -->
+    <permission android:name="android.permission.MANAGE_CRATES"
+                android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to cache content.
          <p>Not for use by third-party applications.
     -->
@@ -3187,13 +3202,6 @@
     <permission android:name="android.permission.BIND_TV_INPUT"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Must be required by an {@link android.service.sms.FinancialSmsService}
-         to ensure that only the system can bind to it.
-         @hide This is not a third-party API (intended for OEMs and system apps).
-    -->
-    <permission android:name="android.permission.BIND_FINANCIAL_SMS_SERVICE"
-        android:protectionLevel="signature" />
-
     <!-- @SystemApi
          Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
          to ensure that only the system can bind to it.
@@ -4347,6 +4355,12 @@
     <permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows preempting sound trigger recognitions for the sake of capturing audio on
+         implementations which do not support running both concurrently.
+         @hide -->
+    <permission android:name="android.permission.PREEMPT_SOUND_TRIGGER"
+                android:protectionLevel="signature|privileged" />
+
     <!-- Must be required by system/priv apps implementing sound trigger detection services
          @hide
          @SystemApi -->
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index fac0789..dac484b 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -281,6 +281,12 @@
         android:label="@string/car_permission_label_enroll_trust"
         android:description="@string/car_permission_desc_enroll_trust" />
 
+    <permission
+        android:name="android.car.permission.CAR_TEST_SERVICE"
+        android:protectionLevel="system|signature"
+        android:label="@string/car_permission_label_car_test_service"
+        android:description="@string/car_permission_desc_car_test_service" />
+
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
diff --git a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
index ebbd40b..3df5b89 100644
--- a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
@@ -84,7 +84,6 @@
         "android.intent.action.SIM_STATE_CHANGED",
         "android.intent.action.DATA_CONNECTION_FAILED",
         "android.intent.action.NETWORK_SET_TIME",
-        "android.intent.action.NETWORK_SET_TIMEZONE",
         "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
         "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED",
         "com.android.internal.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS",
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
index e20b2af..7085078 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
@@ -437,6 +437,7 @@
     @AppModeFull
     public void testStorageTargetingSdk28DoesNotLooseAccessWhenOptingIn() throws Exception {
         installApp(APK_USES_STORAGE_DEFAULT_28, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_OPT_IN_28, null);
 
         assertHasFullStorageAccess();
@@ -446,6 +447,7 @@
     @AppModeFull
     public void testStorageTargetingSdk28DoesNotLooseAccessViaUpdate() throws Exception {
         installApp(APK_USES_STORAGE_DEFAULT_28, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_DEFAULT_29, null);
 
         assertHasFullStorageAccess();
@@ -455,6 +457,7 @@
     @AppModeFull
     public void testStorageTargetingSdk29DoesNotLooseAccessViaUpdate() throws Exception {
         installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_DEFAULT_29, null);
 
         assertHasFullStorageAccess();
@@ -464,6 +467,7 @@
     @AppModeFull
     public void testStorageTargetingSdk29DoesNotLooseAccessWhenOptingIn() throws Exception {
         installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
         installApp(APK_USES_STORAGE_OPT_IN_28, null);
 
         assertHasFullStorageAccess();
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index e2cdb45..f7b726b 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -29,6 +29,8 @@
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
 import android.provider.MediaStore;
 import android.provider.MediaStore.MediaColumns;
 import android.provider.cts.media.MediaStoreUtils;
@@ -186,6 +188,10 @@
         executeShellCommand("bmgr wipe " + backupTransport + " " + packageName, uiAutomation);
     }
 
+    public static void waitForIdle() {
+        MediaStore.waitForIdle(InstrumentationRegistry.getTargetContext().getContentResolver());
+    }
+
     /**
      * Waits until a file exists, or fails.
      *
@@ -201,11 +207,20 @@
         }
     }
 
+    public static File getVolumePath(String volumeName) {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        return context.getSystemService(StorageManager.class)
+                .getStorageVolume(MediaStore.Files.getContentUri(volumeName)).getDirectory();
+    }
+
     public static File stageDir(String volumeName) throws IOException {
         if (MediaStore.VOLUME_EXTERNAL.equals(volumeName)) {
             volumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY;
         }
-        File dir = Environment.buildPath(MediaStore.getVolumePath(volumeName), "Android", "media",
+        final StorageVolume vol = InstrumentationRegistry.getTargetContext()
+                .getSystemService(StorageManager.class)
+                .getStorageVolume(MediaStore.Files.getContentUri(volumeName));
+        File dir = Environment.buildPath(vol.getDirectory(), "Android", "media",
                 "android.provider.cts");
         Log.d(TAG, "stageDir(" + volumeName + "): returning " + dir);
         return dir;
@@ -215,7 +230,10 @@
         if (MediaStore.VOLUME_EXTERNAL.equals(volumeName)) {
             volumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY;
         }
-        return Environment.buildPath(MediaStore.getVolumePath(volumeName),
+        final StorageVolume vol = InstrumentationRegistry.getTargetContext()
+                .getSystemService(StorageManager.class)
+                .getStorageVolume(MediaStore.Files.getContentUri(volumeName));
+        return Environment.buildPath(vol.getDirectory(),
                 Environment.DIRECTORY_DOWNLOADS, "android.provider.cts");
     }
 
@@ -271,19 +289,21 @@
     }
 
     public static Uri scanFile(File file) throws Exception {
-        Uri uri = MediaStore.scanFile(InstrumentationRegistry.getTargetContext(), file);
+        final Uri uri = MediaStore
+                .scanFile(InstrumentationRegistry.getTargetContext().getContentResolver(), file);
         assertWithMessage("no URI for '%s'", file).that(uri).isNotNull();
         return uri;
     }
 
     public static Uri scanFileFromShell(File file) throws Exception {
-        Uri uri = MediaStore.scanFileFromShell(InstrumentationRegistry.getTargetContext(), file);
-        assertWithMessage("no URI for '%s'", file).that(uri).isNotNull();
-        return uri;
+        return scanFile(file);
     }
 
     public static void scanVolume(File file) throws Exception {
-        MediaStore.scanVolume(InstrumentationRegistry.getTargetContext(), file);
+        final StorageVolume vol = InstrumentationRegistry.getTargetContext()
+                .getSystemService(StorageManager.class).getStorageVolume(file);
+        MediaStore.scanVolume(InstrumentationRegistry.getTargetContext().getContentResolver(),
+                vol.getMediaStoreVolumeName());
     }
 
     public static byte[] hash(InputStream in) throws Exception {
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java
index 98df653..a2c6fd6 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java
@@ -209,7 +209,7 @@
     public void testDirectory_InsideSandbox() throws Exception {
         Assume.assumeFalse(MediaStore.VOLUME_EXTERNAL.equals(mVolumeName));
 
-        final File dir = MediaStore.getVolumePath(mVolumeName);
+        final File dir = ProviderTestUtils.getVolumePath(mVolumeName);
         final File file = ProviderTestUtils.stageFile(R.drawable.scenery, Environment.buildPath(dir,
                 "Android", "media", "android.provider.cts", System.nanoTime() + ".jpg"));
         final Uri uri = ProviderTestUtils.scanFile(file);
@@ -301,7 +301,7 @@
         Assume.assumeFalse(MediaStore.VOLUME_EXTERNAL.equals(mVolumeName));
 
         final String displayName = "cts" + System.nanoTime() + ".jpg";
-        final File file = Environment.buildPath(MediaStore.getVolumePath(mVolumeName),
+        final File file = Environment.buildPath(ProviderTestUtils.getVolumePath(mVolumeName),
                 Environment.DIRECTORY_ALARMS, displayName);
         return ProviderTestUtils.scanFileFromShell(
                 ProviderTestUtils.stageFile(R.raw.scenery, file));
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
index 96fcaaf..01ff267 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
@@ -22,18 +22,13 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.app.usage.StorageStatsManager;
 import android.content.ContentResolver;
-import android.content.ContentUris;
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.SystemClock;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
 import android.provider.MediaStore;
-import android.provider.MediaStore.MediaColumns;
 import android.provider.cts.ProviderTestUtils;
 import android.provider.cts.R;
 import android.util.Log;
@@ -49,10 +44,7 @@
 import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
-import java.io.File;
-import java.util.HashSet;
 import java.util.Set;
-import java.util.UUID;
 
 @RunWith(Parameterized.class)
 public class MediaStoreTest {
@@ -181,120 +173,4 @@
         } catch (IllegalArgumentException expected) {
         }
     }
-
-    @Test
-    public void testContributedMedia() throws Exception {
-        // STOPSHIP: remove this once isolated storage is always enabled
-        Assume.assumeTrue(StorageManager.hasIsolatedStorage());
-        Assume.assumeTrue(MediaStore.VOLUME_EXTERNAL_PRIMARY.equals(mVolumeName));
-
-        InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
-                android.Manifest.permission.CLEAR_APP_USER_DATA,
-                android.Manifest.permission.PACKAGE_USAGE_STATS);
-
-        // Start by cleaning up contributed items
-        MediaStore.deleteContributedMedia(getContext(), getContext().getPackageName(),
-                android.os.Process.myUserHandle());
-
-        // Force sync to try updating other views
-        ProviderTestUtils.executeShellCommand("sync");
-        SystemClock.sleep(500);
-
-        // Measure usage before
-        final long beforePackage = getExternalPackageSize();
-        final long beforeTotal = getExternalTotalSize();
-        final long beforeContributed = MediaStore.getContributedMediaSize(getContext(),
-                getContext().getPackageName(), android.os.Process.myUserHandle());
-
-        final long stageSize;
-        try (AssetFileDescriptor fd = getContext().getResources()
-                .openRawResourceFd(R.raw.volantis)) {
-            stageSize = fd.getLength();
-        }
-
-        // Create media both inside and outside sandbox
-        final Uri inside;
-        final Uri outside;
-        final File file = new File(ProviderTestUtils.stageDir(mVolumeName),
-                "cts" + System.nanoTime() + ".jpg");
-        ProviderTestUtils.stageFile(R.raw.volantis, file);
-        inside = ProviderTestUtils.scanFileFromShell(file);
-        outside = ProviderTestUtils.stageMedia(R.raw.volantis, mExternalImages);
-
-        {
-            final HashSet<Long> visible = getVisibleIds(mExternalImages);
-            assertTrue(visible.contains(ContentUris.parseId(inside)));
-            assertTrue(visible.contains(ContentUris.parseId(outside)));
-
-            // Force sync to try updating other views
-            ProviderTestUtils.executeShellCommand("sync");
-            SystemClock.sleep(500);
-
-            final long afterPackage = getExternalPackageSize();
-            final long afterTotal = getExternalTotalSize();
-            final long afterContributed = MediaStore.getContributedMediaSize(getContext(),
-                    getContext().getPackageName(), android.os.Process.myUserHandle());
-
-            assertMostlyEquals(beforePackage + stageSize, afterPackage, SIZE_DELTA);
-            assertMostlyEquals(beforeTotal + stageSize + stageSize, afterTotal, SIZE_DELTA);
-            assertMostlyEquals(beforeContributed + stageSize, afterContributed, SIZE_DELTA);
-        }
-
-        // Delete only contributed items
-        MediaStore.deleteContributedMedia(getContext(), getContext().getPackageName(),
-                android.os.Process.myUserHandle());
-        {
-            final HashSet<Long> visible = getVisibleIds(mExternalImages);
-            assertTrue(visible.contains(ContentUris.parseId(inside)));
-            assertFalse(visible.contains(ContentUris.parseId(outside)));
-
-            // Force sync to try updating other views
-            ProviderTestUtils.executeShellCommand("sync");
-            SystemClock.sleep(500);
-
-            final long afterPackage = getExternalPackageSize();
-            final long afterTotal = getExternalTotalSize();
-            final long afterContributed = MediaStore.getContributedMediaSize(getContext(),
-                    getContext().getPackageName(), android.os.Process.myUserHandle());
-
-            assertMostlyEquals(beforePackage + stageSize, afterPackage, SIZE_DELTA);
-            assertMostlyEquals(beforeTotal + stageSize, afterTotal, SIZE_DELTA);
-            assertMostlyEquals(0, afterContributed, SIZE_DELTA);
-        }
-    }
-
-    private long getExternalPackageSize() throws Exception {
-        final StorageManager storage = getContext().getSystemService(StorageManager.class);
-        final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
-
-        final UUID externalUuid = storage.getUuidForPath(MediaStore.getVolumePath(mVolumeName));
-        return stats.queryStatsForPackage(externalUuid, getContext().getPackageName(),
-                android.os.Process.myUserHandle()).getDataBytes();
-    }
-
-    private long getExternalTotalSize() throws Exception {
-        final StorageManager storage = getContext().getSystemService(StorageManager.class);
-        final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
-
-        final UUID externalUuid = storage.getUuidForPath(MediaStore.getVolumePath(mVolumeName));
-        return stats.queryExternalStatsForUser(externalUuid, android.os.Process.myUserHandle())
-                .getTotalBytes();
-    }
-
-    private HashSet<Long> getVisibleIds(Uri collectionUri) {
-        final HashSet<Long> res = new HashSet<>();
-        try (Cursor c = mContentResolver.query(collectionUri,
-                new String[] { MediaColumns._ID }, null, null)) {
-            while (c.moveToNext()) {
-                res.add(c.getLong(0));
-            }
-        }
-        return res;
-    }
-
-    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/media/MediaStore_DownloadsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_DownloadsTest.java
index 0b6af08..748e284 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_DownloadsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_DownloadsTest.java
@@ -95,9 +95,9 @@
         mExternalImages = MediaStore.Images.Media.getContentUri(mVolumeName);
         mExternalDownloads = MediaStore.Downloads.getContentUri(mVolumeName);
 
-        mDownloadsDir = new File(MediaStore.getVolumePath(resolveVolumeName(mVolumeName)),
+        mDownloadsDir = new File(ProviderTestUtils.getVolumePath(resolveVolumeName(mVolumeName)),
                 Environment.DIRECTORY_DOWNLOADS);
-        mPicturesDir = new File(MediaStore.getVolumePath(resolveVolumeName(mVolumeName)),
+        mPicturesDir = new File(ProviderTestUtils.getVolumePath(resolveVolumeName(mVolumeName)),
                 Environment.DIRECTORY_PICTURES);
         mDownloadsDir.mkdirs();
         mPicturesDir.mkdirs();
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java
index 757766e..2b91cc4 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java
@@ -213,7 +213,7 @@
 
     @Test
     public void testAccess() throws Exception {
-        final String path = MediaStore.getVolumePath(resolveVolumeName(mVolumeName))
+        final String path = ProviderTestUtils.getVolumePath(resolveVolumeName(mVolumeName))
                 .getAbsolutePath();
         final Uri updateUri = ContentUris.withAppendedId(mExternalFiles,
                 ContentUris.parseId(ProviderTestUtils.stageMedia(R.raw.volantis, mExternalImages)));
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
index 5d0199b..874d82c 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
@@ -125,7 +125,7 @@
         mBlue = ProviderTestUtils.stageMedia(R.raw.scenery, mExternalImages);
         mRowsAdded.add(mRed);
         mRowsAdded.add(mBlue);
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
     }
 
     public static void assertMostlyEquals(long expected, long actual, long delta) {
@@ -208,7 +208,7 @@
         String imagePath = c.getString(c.getColumnIndex(Media.DATA));
         c.close();
 
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertExists("image file does not exist", imagePath);
         assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
         assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
@@ -219,7 +219,7 @@
         mContentResolver.delete(stringUri, null, null);
         mRowsAdded.remove(stringUri);
 
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNotExists("image file should no longer exist", imagePath);
         assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
         assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
@@ -306,14 +306,14 @@
                 "test description"));
         long imageId = ContentUris.parseId(uri);
 
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
         assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
 
         // delete the source image and check that the thumbnail is gone too
         mContentResolver.delete(uri, null /* where clause */, null /* where args */);
 
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
         assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
 
@@ -323,7 +323,7 @@
         imageId = ContentUris.parseId(uri);
 
         // query its thumbnail again
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
         assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
 
@@ -334,7 +334,7 @@
                 1, mContentResolver.update(uri, values, null /* where */, null /* where args */));
 
         // image was marked as regular file in the database, which should have deleted its thumbnail
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
         assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
 
@@ -371,7 +371,7 @@
                         Media.insertImage(mContentResolver, src, "cts" + System.nanoTime(), null));
                 mRowsAdded.add(url[i]);
                 long origId = Long.parseLong(url[i].getLastPathSegment());
-                MediaStore.waitForIdle(mContext);
+                ProviderTestUtils.waitForIdle();
                 Bitmap foo = MediaStore.Images.Thumbnails.getThumbnail(mContentResolver,
                         origId, Thumbnails.MICRO_KIND, null);
                 assertNotNull(foo);
@@ -388,7 +388,7 @@
             long remainingId2 = Long.parseLong(url[2].getLastPathSegment());
 
             // check if a thumbnail is still being returned for the image that was removed
-            MediaStore.waitForIdle(mContext);
+            ProviderTestUtils.waitForIdle();
             Bitmap foo = MediaStore.Images.Thumbnails.getThumbnail(mContentResolver,
                     removedId, Thumbnails.MICRO_KIND, null);
             assertNull(foo);
@@ -399,7 +399,7 @@
                         MediaColumns._ID + order);
                 while (c.moveToNext()) {
                     long id = c.getLong(c.getColumnIndex(MediaColumns._ID));
-                    MediaStore.waitForIdle(mContext);
+                    ProviderTestUtils.waitForIdle();
                     foo = MediaStore.Images.Thumbnails.getThumbnail(
                             mContentResolver, id,
                             MediaStore.Images.Thumbnails.MICRO_KIND, null);
@@ -439,7 +439,7 @@
 
         {
             // Thumbnail should be smaller
-            MediaStore.waitForIdle(mContext);
+            ProviderTestUtils.waitForIdle();
             final Bitmap thumb = mContentResolver.loadThumbnail(finalUri, new Size(32, 32), null);
             assertTrue(thumb.getWidth() < full.getWidth());
             assertTrue(thumb.getHeight() < full.getHeight());
@@ -456,7 +456,7 @@
                     MediaStore.Images.Thumbnails.MICRO_KIND
             }) {
                 // Thumbnail should be smaller
-                MediaStore.waitForIdle(mContext);
+                ProviderTestUtils.waitForIdle();
                 final Bitmap thumb = MediaStore.Images.Thumbnails.getThumbnail(mContentResolver,
                         ContentUris.parseId(finalUri), kind, null);
                 assertTrue(thumb.getWidth() < full.getWidth());
@@ -473,11 +473,11 @@
         }
 
         // Wait a few moments for events to settle
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
 
         {
             // Thumbnail should match updated contents
-            MediaStore.waitForIdle(mContext);
+            ProviderTestUtils.waitForIdle();
             final Bitmap thumb = mContentResolver.loadThumbnail(finalUri, new Size(32, 32), null);
             assertColorMostlyEquals(Color.BLUE, thumb.getPixel(16, 16));
         }
@@ -487,7 +487,7 @@
 
         // Thumbnail should no longer exist
         try {
-            MediaStore.waitForIdle(mContext);
+            ProviderTestUtils.waitForIdle();
             mContentResolver.loadThumbnail(finalUri, new Size(32, 32), null);
             fail("Funky; we somehow made a thumbnail out of nothing?");
         } catch (FileNotFoundException expected) {
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
index 379e55d..31b2e7e 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
@@ -116,14 +116,14 @@
         // Don't run the test if the codec isn't supported.
         if (!hasCodec()) {
             // Calling getThumbnail should not generate a new thumbnail.
-            MediaStore.waitForIdle(mContext);
+            ProviderTestUtils.waitForIdle();
             assertNull(Thumbnails.getThumbnail(mResolver, videoId, Thumbnails.MINI_KIND, null));
             Log.i(TAG, "SKIPPING testGetThumbnail(): codec not supported");
             return;
         }
 
         // Calling getThumbnail should generate a new thumbnail.
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNotNull(Thumbnails.getThumbnail(mResolver, videoId, Thumbnails.MINI_KIND, null));
         assertNotNull(Thumbnails.getThumbnail(mResolver, videoId, Thumbnails.MICRO_KIND, null));
 
@@ -144,13 +144,13 @@
         Uri uri = insertVideo();
 
         // request thumbnail creation
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNotNull(Thumbnails.getThumbnail(mResolver, Long.valueOf(uri.getLastPathSegment()),
                 Thumbnails.MINI_KIND, null /* options */));
 
         // delete the source video and check that the thumbnail is gone too
         mResolver.delete(uri, null /* where clause */, null /* where args */);
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNull(Thumbnails.getThumbnail(mResolver, Long.valueOf(uri.getLastPathSegment()),
                 Thumbnails.MINI_KIND, null /* options */));
 
@@ -158,7 +158,7 @@
         uri = insertVideo();
 
         // request thumbnail creation
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNotNull(Thumbnails.getThumbnail(mResolver, Long.valueOf(uri.getLastPathSegment()),
                 Thumbnails.MINI_KIND, null));
 
@@ -169,7 +169,7 @@
                 1, mResolver.update(uri, values, null /* where */, null /* where args */));
 
         // video was marked as regular file in the database, which should have deleted its thumbnail
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         assertNull(Thumbnails.getThumbnail(mResolver, Long.valueOf(uri.getLastPathSegment()),
                 Thumbnails.MINI_KIND, null /* options */));
 
@@ -224,7 +224,7 @@
         }
 
         // Thumbnail should be smaller
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         final Bitmap beforeThumb = mResolver.loadThumbnail(finalUri, new Size(64, 64), null);
         assertTrue(beforeThumb.getWidth() < full.getWidth());
         assertTrue(beforeThumb.getHeight() < full.getHeight());
@@ -237,7 +237,7 @@
                     MediaStore.Video.Thumbnails.FULL_SCREEN_KIND,
                     MediaStore.Video.Thumbnails.MICRO_KIND
             }) {
-                MediaStore.waitForIdle(mContext);
+                ProviderTestUtils.waitForIdle();
                 assertNotNull(MediaStore.Video.Thumbnails.getThumbnail(mResolver,
                         ContentUris.parseId(finalUri), kind, null));
             }
@@ -250,7 +250,7 @@
         }
 
         // Thumbnail should match updated contents
-        MediaStore.waitForIdle(mContext);
+        ProviderTestUtils.waitForIdle();
         final Bitmap afterThumb = mResolver.loadThumbnail(finalUri, new Size(64, 64), null);
         final int afterColor = afterThumb.getPixel(32, 32);
         assertNotColorMostlyEquals(beforeColor, afterColor);
@@ -260,7 +260,7 @@
 
         // Thumbnail should no longer exist
         try {
-            MediaStore.waitForIdle(mContext);
+            ProviderTestUtils.waitForIdle();
             mResolver.loadThumbnail(finalUri, new Size(64, 64), null);
             fail("Funky; we somehow made a thumbnail out of nothing?");
         } catch (FileNotFoundException expected) {
diff --git a/tests/tests/sdkext/Android.bp b/tests/tests/sdkext/Android.bp
new file mode 100644
index 0000000..9ad6c7f
--- /dev/null
+++ b/tests/tests/sdkext/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsSdkExtTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "ctstestrunner-axt",
+    ],
+    srcs: [ "src/**/*.java" ],
+    test_config: "CtsSdkExtTestCases.xml",
+    test_suites: [
+        "cts",
+        "mts",
+        "general-tests",
+    ],
+    sdk_version: "system_current",
+}
diff --git a/tests/tests/sdkext/AndroidManifest.xml b/tests/tests/sdkext/AndroidManifest.xml
new file mode 100644
index 0000000..a6391b5
--- /dev/null
+++ b/tests/tests/sdkext/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.os.ext.cts">
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.os.ext.cts"
+                     android:label="CTS tests of android.os.ext">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/sdkext/CtsSdkExtTestCases.xml b/tests/tests/sdkext/CtsSdkExtTestCases.xml
new file mode 100644
index 0000000..b22653c
--- /dev/null
+++ b/tests/tests/sdkext/CtsSdkExtTestCases.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for SdkExt Tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSdkExtTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.os.ext.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/sdkext/TEST_MAPPING b/tests/tests/sdkext/TEST_MAPPING
new file mode 100644
index 0000000..91947f3
--- /dev/null
+++ b/tests/tests/sdkext/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsSdkExtTestCases"
+    }
+  ]
+}
diff --git a/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java b/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java
new file mode 100644
index 0000000..884f5ef
--- /dev/null
+++ b/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.ext.cts;
+
+import android.os.Build;
+import android.os.ext.SdkExtensions;
+import junit.framework.TestCase;
+
+public class SdkExtensionsTest extends TestCase {
+
+    /** Verify that getExtensionVersion only accepts valid extension SDKs */
+    public void testBadArgument() throws Exception {
+        // R is the first SDK version with extensions.
+        for (int sdk = -1_000_000; sdk < Build.VERSION_CODES.R; sdk++) {
+            try {
+                SdkExtensions.getExtensionVersion(sdk);
+                fail("expected IllegalArgumentException");
+            } catch (IllegalArgumentException expected) { }
+        }
+    }
+
+    /** Verifies that getExtensionVersion only return existing versions */
+    public void testValidValues() throws Exception {
+        for (int sdk = Build.VERSION_CODES.R; sdk <= 1_000_000; sdk++) {
+            // No extension SDKs versions yet.
+            assertEquals(0, SdkExtensions.getExtensionVersion(sdk));
+        }
+    }
+}
diff --git a/tests/tests/security/res/raw/cve_2017_0637.mp4 b/tests/tests/security/res/raw/cve_2017_0637.mp4
new file mode 100644
index 0000000..5765dbb
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_0637.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_13233_hevc.mp4 b/tests/tests/security/res/raw/cve_2017_13233_hevc.mp4
new file mode 100644
index 0000000..8b4858b
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13233_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2106_hevc.mp4 b/tests/tests/security/res/raw/cve_2019_2106_hevc.mp4
new file mode 100644
index 0000000..e8899bd
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2106_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
index 4f7dffc..b621491 100644
--- a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
@@ -20,12 +20,14 @@
 import android.platform.test.annotations.SecurityTest;
 import androidx.test.InstrumentationRegistry;
 
+import android.content.pm.ActivityInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -114,17 +116,25 @@
         private void trigger() {
             Log.i(TAG, "start...");
 
+            String pkg = isCar(mContext) ? "com.android.car.settings" : "com.android.settings";
+            String cls = isCar(mContext)
+                    ? "com.android.car.settings.accounts.AddAccountActivity"
+                    : "com.android.settings.accounts.AddAccountSettings";
             Intent intent = new Intent();
-            intent.setComponent(new ComponentName(
-                    "com.android.settings",
-                    "com.android.settings.accounts.AddAccountSettings"));
+            intent.setComponent(new ComponentName(pkg, cls));
             intent.setAction(Intent.ACTION_RUN);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             String authTypes[] = { SECURITY_CTS_PACKAGE_NAME };
             intent.putExtra("account_types", authTypes);
 
-            mContext.startActivity(intent);
-
+            ActivityInfo info = intent.resolveActivityInfo(
+                    mContext.getPackageManager(), intent.getFlags());
+            // Will throw NullPointerException if activity not found.
+            if (info.exported) {
+                mContext.startActivity(intent);
+            } else {
+                Log.i(TAG, "Activity is not exported");
+            }
             Log.i(TAG, "finsihed.");
         }
 
@@ -356,4 +366,9 @@
             return data;
         }
     }
+
+    private static boolean isCar(Context context) {
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
 }
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index 60e27e6..bccbe59 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -107,6 +107,7 @@
             } catch (SecurityException e) {
                 String msg = e.getMessage();
                 if ((msg == null) || msg.contains("android.permission.DUMP")) {
+                    Log.d(TAG, "Service " + service + " correctly checked permission");
                     // Service correctly checked for DUMP permission, yay
                 } else {
                     // Service is throwing about something else; they're
@@ -115,7 +116,9 @@
                     continue;
                 }
             } catch (TransactionTooLargeException | DeadObjectException e) {
-                // SELinux likely prevented the dump - assume safe
+                // SELinux likely prevented the dump - assume safe, but log anywasy
+                // (as the exception might happens in some devices but not on others)
+                Log.w(TAG, "Service " + service + " threw exception: " + e);
                 continue;
             } finally {
                 out.close();
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 20c7632..4981a09 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -976,6 +976,87 @@
     }
 
     @SecurityTest(minPatchLevel = "2018-04")
+    public void testStagefright_cve_2017_13279() throws Exception {
+      Thread server = new Thread() {
+        @Override
+        public void run(){
+          try (ServerSocket serverSocket = new ServerSocket(8080);
+            Socket conn = serverSocket.accept()){
+              OutputStream stream = conn.getOutputStream();
+              byte http[] = ("HTTP/1.0 200 OK\r\nContent-Type: application/x-mpegURL\r\n\r\n"
+                           + "#EXTM3U\n#EXT-X-STREAM-INF:\n").getBytes();
+              stream.write(http);
+              while(!conn.isClosed())
+                stream.write(("a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\n").getBytes());
+            }
+          catch(IOException e){
+          }
+        }
+      };
+      server.start();
+      String uri = "http://127.0.0.1:8080/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+                 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"
+                 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.m3u8";
+      final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+
+      LooperThread t = new LooperThread(new Runnable() {
+          @Override
+          public void run() {
+
+              MediaPlayer mp = new MediaPlayer();
+              mp.setOnErrorListener(mpcl);
+              mp.setOnPreparedListener(mpcl);
+              mp.setOnCompletionListener(mpcl);
+              RenderTarget renderTarget = RenderTarget.create();
+              Surface surface = renderTarget.getSurface();
+              mp.setSurface(surface);
+              AssetFileDescriptor fd = null;
+              try {
+                mp.setDataSource(uri);
+                mp.prepareAsync();
+              } catch (IOException e) {
+                Log.e(TAG, e.toString());
+              } finally {
+                  closeQuietly(fd);
+              }
+
+              Looper.loop();
+              mp.release();
+          }
+      });
+      t.start();
+      Thread.sleep(60000); // Poc takes a while to crash mediaserver, waitForError
+                           // doesn't wait long enough
+      assertFalse("Device *IS* vulnerable to CVE-2017-13279",
+                  mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+      t.stopLooper();
+      t.join(); // wait for thread to exit so we're sure the player was released
+      server.join();
+    }
+
+    @SecurityTest(minPatchLevel = "2018-04")
     public void testStagefright_cve_2017_13276() throws Exception {
         doStagefrightTest(R.raw.cve_2017_13276);
     }
@@ -1000,6 +1081,24 @@
      before any existing test methods
      ***********************************************************/
 
+    @SecurityTest(minPatchLevel = "2018-02")
+    public void testStagefright_cve_2017_13233() throws Exception {
+        doStagefrightTestRawBlob(R.raw.cve_2017_13233_hevc, "video/hevc", 640,
+                480);
+    }
+
+    @SecurityTest(minPatchLevel = "2019-07")
+    public void testStagefright_cve_2019_2106() throws Exception {
+        int[] frameSizes = {943, 3153};
+        doStagefrightTestRawBlob(R.raw.cve_2019_2106_hevc, "video/hevc", 320,
+                240, frameSizes);
+    }
+
+    @SecurityTest(minPatchLevel = "2017-06")
+    public void testStagefright_cve_2017_0637() throws Exception {
+        doStagefrightTest(R.raw.cve_2017_0637, 2 * 72000);
+    }
+
     @SecurityTest(minPatchLevel = "2018-09")
     public void testStagefright_cve_2018_11287() throws Exception {
         doStagefrightTest(R.raw.cve_2018_11287, 180000);
diff --git a/tests/tests/selinux/TEST_MAPPING b/tests/tests/selinux/TEST_MAPPING
new file mode 100644
index 0000000..a8bae77
--- /dev/null
+++ b/tests/tests/selinux/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsSelinuxEphemeralTestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdk25TestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdk27TestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdk28TestCases"
+    },
+    {
+      "name": "CtsSelinuxTargetSdkCurrentTestCases"
+    }
+  ]
+}
+
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index 137c003..dc414ef 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -59,6 +59,13 @@
      */
     private static final int COLOR_COMPONENT_ERROR_MARGIN = 20;
 
+    /**
+     * It's possible for the device to have color sampling enabled in the nav bar -- in that
+     * case we need to pick a background color that would result in the same dark icon tint
+     * that matches the default visibility flags used when color sampling is not enabled.
+     */
+    private static final int LIGHT_BG_COLOR = Color.rgb(255, 128, 128);
+
     private final String NOTIFICATION_TAG = "TEST_TAG";
     private final String NOTIFICATION_CHANNEL_ID = "test_channel";
     private final String NOTIFICATION_GROUP_KEY = "test_group";
@@ -92,11 +99,11 @@
             mNm.notify(NOTIFICATION_TAG, i, noti1.build());
         }
 
-        requestLightBars(Color.RED /* background */);
+        requestLightBars(LIGHT_BG_COLOR);
         Thread.sleep(WAIT_TIME);
 
         Bitmap bitmap = takeStatusBarScreenshot(mActivityRule.getActivity());
-        Stats s = evaluateLightBarBitmap(bitmap, Color.RED /* background */, 0);
+        Stats s = evaluateLightBarBitmap(bitmap, LIGHT_BG_COLOR, 0);
         assertLightStats(bitmap, s);
 
         mNm.cancelAll();
@@ -107,7 +114,7 @@
     public void testLightNavigationBar() throws Throwable {
         assumeHasColoredNavigationBar(mActivityRule);
 
-        requestLightBars(Color.RED /* background */);
+        requestLightBars(LIGHT_BG_COLOR);
         Thread.sleep(WAIT_TIME);
 
         // Inject a cancelled interaction with the nav bar to ensure it is at full opacity.
@@ -118,7 +125,7 @@
 
         LightBarActivity activity = mActivityRule.getActivity();
         Bitmap bitmap = takeNavigationBarScreenshot(activity);
-        Stats s = evaluateLightBarBitmap(bitmap, Color.RED /* background */, activity.getBottom());
+        Stats s = evaluateLightBarBitmap(bitmap, LIGHT_BG_COLOR, activity.getBottom());
         assertLightStats(bitmap, s);
     }
 
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
index c0b4673..7428130 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
@@ -33,5 +33,12 @@
                 <action android:name="android.telecom.cts.screeningtestapp.ACTION_CONTROL_CALL_SCREENING_SERVICE" />
             </intent-filter>
         </service>
+        <activity android:name=".CtsPostCallActivity"
+                  android:label="CtsPostCallActivity">
+            <intent-filter>
+                <action android:name="android.telecom.action.POST_CALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
index 8da8769..9e7cc2c 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
@@ -26,4 +26,10 @@
             boolean shouldSkipCall, boolean shouldSkipCallLog, boolean shouldSkipNotification);
 
     boolean waitForBind();
+
+    boolean waitForActivity();
+
+    String getCachedHandle();
+
+    int getCachedDisconnectCause();
 }
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
index 954d9af..96f4173 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
@@ -52,6 +52,7 @@
                             .setSkipNotification(false)
                             .build();
                     mBindingLatch = new CountDownLatch(1);
+                    CtsPostCallActivity.resetPostCallActivity();
                 }
 
                 @Override
@@ -78,6 +79,21 @@
                         return false;
                     }
                 }
+
+                @Override
+                public boolean waitForActivity() {
+                    return CtsPostCallActivity.waitForActivity();
+                }
+
+                @Override
+                public String getCachedHandle() {
+                    return CtsPostCallActivity.getCachedHandle().getSchemeSpecificPart();
+                }
+
+                @Override
+                public int getCachedDisconnectCause() {
+                    return CtsPostCallActivity.getCachedDisconnectCause();
+                }
             };
 
     private CallScreeningService.CallResponse mCallResponse =
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
new file mode 100644
index 0000000..ac5ce01
--- /dev/null
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts.screeningtestapp;
+
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class CtsPostCallActivity extends Activity {
+    private static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
+    private static final int DEFAULT_DISCONNECT_CAUSE = -1;
+    private static final long TEST_TIMEOUT = 5000;
+
+    private static Uri cachedHandle;
+    private static int cachedDisconnectCause;
+    private static CountDownLatch sLatch = new CountDownLatch(1);
+
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        final Intent intent = getIntent();
+        final String action = intent != null ? intent.getAction() : null;
+        if (ACTION_POST_CALL.equals(action)) {
+            cachedHandle = intent.getParcelableExtra(EXTRA_HANDLE);
+            cachedDisconnectCause = intent
+                    .getIntExtra(EXTRA_DISCONNECT_CAUSE, DEFAULT_DISCONNECT_CAUSE);
+            sLatch.countDown();
+        }
+    }
+
+    public static Uri getCachedHandle() {
+        return cachedHandle;
+    }
+
+    public static int getCachedDisconnectCause() {
+        return cachedDisconnectCause;
+    }
+
+    public static void resetPostCallActivity() {
+        sLatch = new CountDownLatch(1);
+        cachedHandle = null;
+        cachedDisconnectCause = DEFAULT_DISCONNECT_CAUSE;
+    }
+
+    public static boolean waitForActivity() {
+        try {
+            return sLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
index d498de0..7d81184 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
@@ -76,10 +76,10 @@
             mCarModeIncallServiceControlTwo.reset();
         }
 
+        assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
+
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .dropShellPermissionIdentity();
-
-        assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
     }
 
     /**
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index e7dddd2..10cd943 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -400,7 +400,11 @@
     }
 
     private Uri blockNumber(Uri phoneNumberUri) {
-        return insertBlockedNumber(mContext, phoneNumberUri.getSchemeSpecificPart());
+        Uri number = insertBlockedNumber(mContext, phoneNumberUri.getSchemeSpecificPart());
+        if (number == null) {
+            fail("Failed to insert into blocked number provider");
+        }
+        return number;
     }
 
     private int unblockNumber(Uri uri) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 532c69e..76c7c72 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -273,6 +273,32 @@
         assertFalse(mCallScreeningControl.waitForBind());
     }
 
+    public void testNoPostCallActivityWithoutRole() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        removeRoleHolder(ROLE_CALL_SCREENING, CtsCallScreeningService.class.getPackage().getName());
+        addIncomingAndVerifyAllowed(false);
+        assertFalse(mCallScreeningControl.waitForActivity());
+    }
+
+    public void testAllowCall() throws Exception {
+        mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
+                false /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
+        addIncomingAndVerifyAllowed(false /* addContact */);
+        assertTrue(mCallScreeningControl.waitForActivity());
+    }
+
+    public void testNoPostCallActivityWhenBlocked() throws Exception {
+        mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+                true /* shouldRejectCall */, false /* shouldSilenceCall */,
+                false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+        addIncomingAndVerifyBlocked(false /* addContact */);
+        assertFalse(mCallScreeningControl.waitForActivity());
+    }
+
     private void placeOutgoingCall(boolean addContact) throws Exception {
         // Setup content observer to notify us when we call log entry is added.
         CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
diff --git a/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java
index c815b75..3ec5d83 100644
--- a/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java
+++ b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java
@@ -43,7 +43,7 @@
 
         @Override
         public boolean isUnbound() {
-            return CtsCarModeInCallService.isBound();
+            return CtsCarModeInCallService.isUnbound();
         }
 
         @Override
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
index 73fa25e..d4ae5d0 100644
--- a/tests/tests/telephony/OWNERS
+++ b/tests/tests/telephony/OWNERS
@@ -4,11 +4,10 @@
 jackyu@google.com
 rgreenwalt@google.com
 refuhoo@google.com
-mpq@google.com
 jminjie@google.com
 shuoq@google.com
 hallliu@google.com
 tgunn@google.com
 breadley@google.com
-paulye@google.com
 nazaninb@google.com
+sarahchin@google.com
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
index 6a34175..86c8305 100644
--- a/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
@@ -28,4 +28,8 @@
     boolean isRcsFeatureCreated();
     boolean isMmTelFeatureCreated();
     void resetState();
-}
\ No newline at end of file
+    void updateImsRegistration(int radioTech);
+    void notifyRcsCapabilitiesStatusChanged(int capability);
+    boolean isRcsCapable(int capability, int radioTech);
+    boolean isRcsAvailable(int capability);
+}
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
index 48e71a3..1f1c747 100644
--- a/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
@@ -20,7 +20,9 @@
 import android.os.IBinder;
 import android.telephony.ims.cts.ImsUtils;
 import android.telephony.ims.cts.TestImsService;
+import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
 /**
@@ -40,18 +42,41 @@
         public boolean waitForLatchCountdown(int latchIndex) {
             return TestExternalImsService.this.waitForLatchCountdown(latchIndex);
         }
+
         public void setFeatureConfig(ImsFeatureConfiguration f) {
             TestExternalImsService.this.setFeatureConfig(f);
         }
+
         public boolean isRcsFeatureCreated() {
             return (getRcsFeature() != null);
         }
+
         public boolean isMmTelFeatureCreated() {
             return (getMmTelFeature() != null);
         }
+
         public void resetState() {
             TestExternalImsService.this.resetState();
         }
+
+        public void updateImsRegistration(int imsRadioTech) {
+            ImsRegistrationImplBase imsReg = TestExternalImsService.this.getImsRegistration();
+            imsReg.onRegistered(imsRadioTech);
+        }
+
+        public void notifyRcsCapabilitiesStatusChanged(int capability) {
+            RcsImsCapabilities capabilities = new RcsImsCapabilities(capability);
+            getRcsFeature().notifyCapabilitiesStatusChanged(capabilities);
+        }
+
+        public boolean isRcsCapable(int capability, int radioTech) {
+            return getRcsFeature().queryCapabilityConfiguration(capability, radioTech);
+        }
+
+        public boolean isRcsAvailable(int capability) {
+            RcsImsCapabilities capabilityStatus = getRcsFeature().queryCapabilityStatus();
+            return capabilityStatus.isCapable(capability);
+        }
     }
 
     @Override
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
index aeeb9b1..83aaa0b 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
@@ -51,6 +51,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.io.IOException;
@@ -145,6 +146,7 @@
     }
 
     @SecurityTest
+    @Ignore // TODO(b/146238285) -- Appop commands not working.
     @Test
     public void testRevokePermission() {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java
index 211f9ff..6b1ca39 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java
@@ -67,6 +67,12 @@
 
     @Before
     public void setUp() {
+        TEST_GEOS.add(new CbGeoUtils.Geometry() {
+            @Override
+            public boolean contains(CbGeoUtils.LatLng p) {
+                return false;
+            }
+        });
         mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
                 TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY, TEST_PRIORITY,
                 TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index c272764..328fe82 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -366,24 +366,6 @@
     }
 
     @Test
-    public void testGetSmsMessagesForFinancialAppPermissionNotRequested() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-
-        try {
-            getSmsManager().getSmsMessagesForFinancialApp(new Bundle(),
-                    getInstrumentation().getContext().getMainExecutor(),
-                    new SmsManager.FinancialSmsCallback() {
-                        public void onFinancialSmsMessages(CursorWindow msgs) {
-                            assertNull(msgs);
-                            latch.countDown();
-                    }});
-            assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
-        } catch (Exception e) {
-            // do nothing
-        }
-    }
-
-    @Test
     public void testGetSmsMessagesForFinancialAppPermissionRequestedNotGranted() throws Exception {
         CompletableFuture<Bundle> callbackResult = new CompletableFuture<>();
 
@@ -690,6 +672,9 @@
 
     private void blockNumber(String number) {
         mBlockedNumberUri = insertBlockedNumber(mContext, number);
+        if (mBlockedNumberUri == null) {
+            fail("Failed to insert into blocked number provider.");
+        }
     }
 
     private void unblockNumber(Uri uri) {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 0169b4b..052a21f 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -467,6 +467,8 @@
         mTelephonyManager.isVoicemailVibrationEnabled(defaultAccount);
         mTelephonyManager.getSubscriptionId(defaultAccount);
         mTelephonyManager.getCarrierConfig();
+        ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                (tm) -> tm.isAnyRadioPoweredOn());
         TelephonyManager.getDefaultRespondViaMessageApplication(getContext(), false);
     }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
index caf9b4c..37228c8 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
@@ -34,6 +34,8 @@
         KNOWN_TELEPHONY_PACKAGES.add("com.android.providers.telephony");
         KNOWN_TELEPHONY_PACKAGES.add("com.android.ons");
         KNOWN_TELEPHONY_PACKAGES.add("com.android.cellbroadcastservice");
+        KNOWN_TELEPHONY_PACKAGES.add("com.android.cellbroadcastreceiver");
+        KNOWN_TELEPHONY_PACKAGES.add("com.android.shell");
     }
 
     @Test
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
index 9215672..dcc0f9a 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
@@ -26,6 +26,7 @@
 import android.telephony.cts.TelephonyUtils;
 import android.telephony.cts.externalimsservice.ITestExternalImsService;
 import android.telephony.cts.externalimsservice.TestExternalImsService;
+import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 import android.util.Log;
 
@@ -56,6 +57,7 @@
     private static final String COMMAND_CARRIER_SERVICE_IDENTIFIER = "-c ";
     private static final String COMMAND_DEVICE_SERVICE_IDENTIFIER = "-d ";
     private static final String COMMAND_SLOT_IDENTIFIER = "-s ";
+    private static final String COMMAND_FEATURE_IDENTIFIER = "-f ";
     private static final String COMMAND_ENABLE_IMS = "ims enable ";
     private static final String COMMAND_DISABLE_IMS = "ims disable ";
 
@@ -106,7 +108,9 @@
         private static final int CONNECTION_TYPE_DEFAULT_SMS_APP = 3;
 
         private boolean mIsServiceOverridden = false;
-        private String mOrigServicePackage;
+        private String mOrigMmTelServicePackage;
+        private String mOrigRcsServicePackage;
+        private String mOrigSmsPackage;
         private int mConnectionType;
         private int mSlotId;
         Connection(int connectionType, int slotId) {
@@ -118,7 +122,7 @@
             mIsServiceOverridden = true;
             switch (mConnectionType) {
                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
-                    setCarrierImsService("");
+                    setCarrierImsService("none");
                     break;
                 }
                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
@@ -152,21 +156,28 @@
             if (!mIsServiceOverridden) {
                 return;
             }
-            if (mOrigServicePackage == null) {
-                mOrigServicePackage = "";
+
+            if (mOrigRcsServicePackage == null) {
+                mOrigRcsServicePackage = "";
+            }
+
+            if (mOrigMmTelServicePackage == null) {
+                mOrigMmTelServicePackage = "";
             }
 
             switch (mConnectionType) {
                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
-                    setCarrierImsService(mOrigServicePackage);
+                    setCarrierImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
+                    setCarrierImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
                     break;
                 }
                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
-                    setDeviceImsService(mOrigServicePackage);
+                    setDeviceImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
+                    setDeviceImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
                     break;
                 }
                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
-                    setDefaultSmsApp(mOrigServicePackage);
+                    setDefaultSmsApp(mOrigSmsPackage);
                     break;
                 }
             }
@@ -175,15 +186,17 @@
         private void storeOriginalPackage() throws Exception {
             switch (mConnectionType) {
                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
-                    mOrigServicePackage = getOriginalCarrierService();
+                    mOrigMmTelServicePackage = getOriginalMmTelCarrierService();
+                    mOrigRcsServicePackage = getOriginalRcsCarrierService();
                     break;
                 }
                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
-                    mOrigServicePackage = getOriginalDeviceService();
+                    mOrigMmTelServicePackage = getOriginalMmTelDeviceService();
+                    mOrigRcsServicePackage = getOriginalRcsDeviceService();
                     break;
                 }
                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
-                    mOrigServicePackage = getDefaultSmsApp();
+                    mOrigSmsPackage = getDefaultSmsApp();
                     break;
                 }
             }
@@ -191,18 +204,40 @@
 
         private boolean setDeviceImsService(String packageName) throws Exception {
             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
-                    constructSetImsServiceOverrideCommand(false, packageName));
+                    constructSetImsServiceOverrideCommand(false, packageName, new int[] {
+                            ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
             if (ImsUtils.VDBG) {
-                Log.d(TAG, "setDeviceImsService result: " + result);
+                Log.d(TAG, "setDeviceMmTelImsService result: " + result);
             }
             return "true".equals(result);
         }
 
         private boolean setCarrierImsService(String packageName) throws Exception {
             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
-                    constructSetImsServiceOverrideCommand(true, packageName));
+                    constructSetImsServiceOverrideCommand(true, packageName, new int[] {
+                            ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
             if (ImsUtils.VDBG) {
-                Log.d(TAG, "setCarrierImsService result: " + result);
+                Log.d(TAG, "setCarrierMmTelImsService result: " + result);
+            }
+            return "true".equals(result);
+        }
+
+        private boolean setDeviceImsService(String packageName, int featureType) throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructSetImsServiceOverrideCommand(false, packageName,
+                            new int[]{featureType}));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "setDeviceMmTelImsService result: " + result);
+            }
+            return "true".equals(result);
+        }
+
+        private boolean setCarrierImsService(String packageName, int featureType) throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructSetImsServiceOverrideCommand(true, packageName,
+                            new int[]{featureType}));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "setCarrierMmTelImsService result: " + result);
             }
             return "true".equals(result);
         }
@@ -249,36 +284,67 @@
                     TestImsService.LATCH_FEATURES_READY);
         }
 
-        private String getOriginalCarrierService() throws Exception {
+        private String getOriginalMmTelCarrierService() throws Exception {
             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
-                    constructGetImsServiceCommand(true));
+                    constructGetImsServiceCommand(true, ImsFeature.FEATURE_MMTEL));
             if (ImsUtils.VDBG) {
-                Log.d(TAG, "getOriginalCarrierService result: " + result);
+                Log.d(TAG, "getOriginalMmTelCarrierService result: " + result);
             }
             return result;
         }
 
-        private String getOriginalDeviceService() throws Exception {
+        private String getOriginalRcsCarrierService() throws Exception {
             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
-                    constructGetImsServiceCommand(false));
+                    constructGetImsServiceCommand(true, ImsFeature.FEATURE_RCS));
             if (ImsUtils.VDBG) {
-                Log.d(TAG, "getOriginalDeviceService result: " + result);
+                Log.d(TAG, "getOriginalRcsCarrierService result: " + result);
+            }
+            return result;
+        }
+
+        private String getOriginalMmTelDeviceService() throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructGetImsServiceCommand(false, ImsFeature.FEATURE_MMTEL));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "getOriginalMmTelDeviceService result: " + result);
+            }
+            return result;
+        }
+
+        private String getOriginalRcsDeviceService() throws Exception {
+            String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+                    constructGetImsServiceCommand(false, ImsFeature.FEATURE_RCS));
+            if (ImsUtils.VDBG) {
+                Log.d(TAG, "getOriginalRcsDeviceService result: " + result);
             }
             return result;
         }
 
         private String constructSetImsServiceOverrideCommand(boolean isCarrierService,
-                String packageName) {
+                String packageName, int[] featureTypes) {
             return COMMAND_BASE + COMMAND_SET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
                     + (isCarrierService
                         ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
+                    + COMMAND_FEATURE_IDENTIFIER + getFeatureTypesString(featureTypes) + " "
                     + packageName;
         }
 
-        private String constructGetImsServiceCommand(boolean isCarrierService) {
+        private String constructGetImsServiceCommand(boolean isCarrierService, int featureType) {
             return COMMAND_BASE + COMMAND_GET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
                     + (isCarrierService
-                        ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER);
+                        ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
+                    + COMMAND_FEATURE_IDENTIFIER + featureType;
+        }
+
+        private String getFeatureTypesString(int[] featureTypes) {
+            if (featureTypes.length == 0) return "";
+            StringBuilder builder = new StringBuilder();
+            builder.append(featureTypes[0]);
+            for (int i = 1; i < featureTypes.length; i++) {
+                builder.append(",");
+                builder.append(featureTypes[i]);
+            }
+            return builder.toString();
         }
     }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index d6698c9..1772152 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -40,13 +40,17 @@
 import android.telephony.TelephonyManager;
 import android.telephony.cts.AsyncSmsMessageListener;
 import android.telephony.cts.SmsReceiverHelper;
+import android.telephony.cts.externalimsservice.ITestExternalImsService;
 import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsRcsManager;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Base64;
@@ -77,6 +81,10 @@
 
     private static ImsServiceConnector sServiceConnector;
 
+    private static final int RCS_CAP_NONE = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
+    private static final int RCS_CAP_OPTIONS = RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE;
+    private static final int RCS_CAP_PRESENCE = RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
+
     private static final String MSG_CONTENTS = "hi";
     private static final String EXPECTED_RECEIVED_MESSAGE = "foo5";
     private static final String DEST_NUMBER = "5555554567";
@@ -899,6 +907,107 @@
     }
 
     @Test
+    public void testRcsCapabilityStatusCallback() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        if (imsManager == null) {
+            fail("Cannot find IMS service");
+        }
+
+        // Connect to device ImsService with RcsFeature
+        triggerFrameworkConnectToDeviceImsServiceBindRcsFeature();
+
+        int registrationTech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+        ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
+
+        ITestExternalImsService testImsService = sServiceConnector.getExternalService();
+        // Wait for the framework to set the capabilities on the ImsService
+        testImsService.waitForLatchCountdown(TestImsService.LATCH_RCS_CAP_SET);
+        // Make sure we start off with none-capability
+        testImsService.updateImsRegistration(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_NONE);
+
+        // Make sure the capabilities match the API getter for capabilities
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        // Latch will count down here (we callback on the state during registration).
+        try {
+            automan.adoptShellPermissionIdentity();
+            // Make sure we are tracking voice capability over LTE properly.
+            assertEquals(testImsService.isRcsAvailable(RCS_CAP_PRESENCE),
+                    imsRcsManager.isAvailable(RCS_CAP_PRESENCE));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // Trigger carrier config changed
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true);
+        bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true);
+        overrideCarrierConfig(bundle);
+
+        // The carrier config changed should trigger RcsFeature#changeEnabledCapabilities
+        try {
+            automan.adoptShellPermissionIdentity();
+            // Checked by isCapable api to make sure RcsFeature#changeEnabledCapabilities is called
+            assertTrue(ImsUtils.retryUntilTrue(() ->
+                    imsRcsManager.isCapable(RCS_CAP_OPTIONS, registrationTech)));
+            assertTrue(ImsUtils.retryUntilTrue(() ->
+                    imsRcsManager.isCapable(RCS_CAP_PRESENCE, registrationTech)));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // A queue to receive capability changed
+        LinkedBlockingQueue<RcsImsCapabilities> mQueue = new LinkedBlockingQueue<>();
+        ImsRcsManager.AvailabilityCallback callback = new ImsRcsManager.AvailabilityCallback() {
+            @Override
+            public void onAvailabilityChanged(RcsImsCapabilities capabilities) {
+                mQueue.offer(capabilities);
+            }
+        };
+
+        // Latch will count down here (we callback on the state during registration).
+        try {
+            automan.adoptShellPermissionIdentity();
+            imsRcsManager.registerRcsAvailabilityCallback(getContext().getMainExecutor(), callback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // We should not have any availabilities here, we notified the framework earlier.
+        RcsImsCapabilities capCb = waitForResult(mQueue);
+
+        // The SIP OPTIONS capability from onAvailabilityChanged should be disabled.
+        // Moreover, ImsRcsManager#isAvailable also return FALSE with SIP OPTIONS
+        assertTrue(capCb.isCapable(RCS_CAP_NONE));
+        try {
+            automan.adoptShellPermissionIdentity();
+            assertFalse(imsRcsManager.isAvailable(RCS_CAP_OPTIONS));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // Notify the SIP OPTIONS capability status changed
+        testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_OPTIONS);
+        capCb = waitForResult(mQueue);
+
+        // The SIP OPTIONS capability from onAvailabilityChanged should be enabled.
+        // Verify ImsRcsManager#isAvailable also return true with SIP OPTIONS
+        assertTrue(capCb.isCapable(RCS_CAP_OPTIONS));
+        try {
+            automan.adoptShellPermissionIdentity();
+            assertTrue(imsRcsManager.isAvailable(RCS_CAP_OPTIONS));
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        overrideCarrierConfig(null);
+    }
+
+    @Test
     public void testProvisioningManagerSetConfig() throws Exception {
         if (!ImsUtils.shouldTestImsService()) {
             return;
@@ -1037,6 +1146,20 @@
                 sServiceConnector.getCarrierService().getMmTelFeature());
     }
 
+    private void triggerFrameworkConnectToDeviceImsServiceBindRcsFeature() throws Exception {
+        // Connect to the ImsService with the RCS feature.
+        assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+                .build()));
+        // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        sServiceConnector.getExternalService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS);
+        // Make sure the RcsFeature was created in the test service.
+        assertTrue("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
+                + "called!", sServiceConnector.getExternalService().isRcsFeatureCreated());
+    }
+
     private void verifyRegistrationState(RegistrationManager regManager, int expectedState)
             throws Exception {
         LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
index 406d61a..6562d01 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
@@ -33,7 +33,6 @@
 import java.util.concurrent.Callable;
 
 public class ImsUtils {
-    public static final String TAG = "GtsImsServiceTests";
     public static final boolean VDBG = false;
 
     // ImsService rebind has an exponential backoff capping at 64 seconds. Wait for 70 seconds to
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
index c21d8ba..c793d00 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -58,8 +58,10 @@
     public static final int LATCH_REMOVE_MMTEL = 5;
     public static final int LATCH_REMOVE_RCS = 6;
     public static final int LATCH_MMTEL_READY = 7;
-    public static final int LATCH_MMTEL_CAP_SET = 8;
-    private static final int LATCH_MAX = 9;
+    public static final int LATCH_RCS_READY = 8;
+    public static final int LATCH_MMTEL_CAP_SET = 9;
+    public static final int LATCH_RCS_CAP_SET = 10;
+    private static final int LATCH_MAX = 11;
     protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
     static {
         for (int i = 0; i < LATCH_MAX; i++) {
@@ -123,12 +125,27 @@
         public RcsFeature createRcsFeature(int slotId) {
             synchronized (mLock) {
                 countDownLatch(LATCH_CREATE_RCS);
-                mTestRcsFeature = new TestRcsFeature(() -> {
-                    synchronized (mLock) {
-                        countDownLatch(LATCH_REMOVE_RCS);
-                        mTestRcsFeature = null;
-                    }
-                });
+                mTestRcsFeature = new TestRcsFeature(
+                        //onReady
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_RCS_READY);
+                            }
+                        },
+                        //onRemoved
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_REMOVE_RCS);
+                                mTestRcsFeature = null;
+                            }
+                        },
+                        //onCapabilitiesSet
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_RCS_CAP_SET);
+                            }
+                        }
+                        );
                 return mTestRcsFeature;
             }
         }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
index 8781550..9752258 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
@@ -16,18 +16,77 @@
 
 package android.telephony.ims.cts;
 
+import android.telephony.ims.feature.CapabilityChangeRequest;
 import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import java.util.List;
 
 public class TestRcsFeature extends RcsFeature {
+    private static final String TAG = "CtsTestImsService";
 
+    private final TestImsService.ReadyListener mReadyListener;
     private final TestImsService.RemovedListener mRemovedListener;
+    private final TestImsService.CapabilitiesSetListener mCapSetListener;
 
-    TestRcsFeature(TestImsService.RemovedListener listener) {
+    private RcsImsCapabilities mCapabilities =
+            new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE);
+
+    TestRcsFeature(TestImsService.ReadyListener readyListener,
+            TestImsService.RemovedListener listener,
+            TestImsService.CapabilitiesSetListener setListener) {
+        mReadyListener = readyListener;
         mRemovedListener = listener;
+        mCapSetListener = setListener;
+
+        setFeatureState(STATE_READY);
+    }
+
+    @Override
+    public void onFeatureReady() {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.onFeatureReady called");
+        }
+        mReadyListener.onReady();
     }
 
     @Override
     public void onFeatureRemoved() {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.onFeatureRemoved called");
+        }
         mRemovedListener.onRemoved();
     }
+
+
+    @Override
+    public boolean queryCapabilityConfiguration(int capability, int radioTech) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.queryCapabilityConfiguration called with capability: "
+                    + capability);
+        }
+        return mCapabilities.isCapable(capability);
+    }
+
+    @Override
+    public void changeEnabledCapabilities(CapabilityChangeRequest request,
+            CapabilityCallbackProxy c) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.changeEnabledCapabilities");
+        }
+        List<CapabilityChangeRequest.CapabilityPair> pairs = request.getCapabilitiesToEnable();
+        for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+            if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                mCapabilities.addCapabilities(pair.getCapability());
+            }
+        }
+        pairs = request.getCapabilitiesToDisable();
+        for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+            if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                mCapabilities.removeCapabilities(pair.getCapability());
+            }
+        }
+        mCapSetListener.onSet();
+    }
 }
diff --git a/tests/tests/tethering/Android.bp b/tests/tests/tethering/Android.bp
new file mode 100644
index 0000000..0f98125
--- /dev/null
+++ b/tests/tests/tethering/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsTetheringTest",
+    defaults: ["cts_defaults"],
+
+    libs: [
+        "android.test.base.stubs",
+    ],
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    static_libs: [
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "junit",
+        "junit-params",
+    ],
+
+    // Change to system current when TetheringManager move to bootclass path.
+    platform_apis: true,
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+        "mts",
+    ],
+
+}
diff --git a/tests/tests/tethering/AndroidManifest.xml b/tests/tests/tethering/AndroidManifest.xml
new file mode 100644
index 0000000..665002e
--- /dev/null
+++ b/tests/tests/tethering/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.tethering.cts">
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.tethering.cts"
+                     android:label="CTS tests of android.tethering">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/tethering/AndroidTest.xml b/tests/tests/tethering/AndroidTest.xml
new file mode 100644
index 0000000..217d53a
--- /dev/null
+++ b/tests/tests/tethering/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Tethering test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="not-shardable" value="true" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTetheringTest.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.tethering.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
new file mode 100644
index 0000000..9efb8f3
--- /dev/null
+++ b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.tethering.test;
+
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.os.ConditionVariable;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class TetheringManagerTest {
+
+    private Context mContext;
+
+    private ConnectivityManager mCM;
+
+    private TetherChangeReceiver mTetherChangeReceiver;
+
+    private String[] mTetheredList;
+
+    private static final int DEFAULT_TIMEOUT_MS = 60_000;
+
+    @Before
+    public void setUp() throws Exception {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity();
+        mContext = InstrumentationRegistry.getContext();
+        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mTetherChangeReceiver = new TetherChangeReceiver();
+        final IntentFilter filter = new IntentFilter(
+                ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+        final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter);
+        if (intent != null) mTetherChangeReceiver.onReceive(null, intent);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mContext.unregisterReceiver(mTetherChangeReceiver);
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    private class TetherChangeReceiver extends BroadcastReceiver {
+        private class TetherState {
+            final ArrayList<String> mAvailable;
+            final ArrayList<String> mActive;
+            final ArrayList<String> mErrored;
+
+            TetherState(Intent intent) {
+                mAvailable = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+                mActive = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_ACTIVE_TETHER);
+                mErrored = intent.getStringArrayListExtra(
+                        ConnectivityManager.EXTRA_ERRORED_TETHER);
+            }
+        }
+
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
+                mResult.add(new TetherState(intent));
+            }
+        }
+
+        public final LinkedBlockingQueue<TetherState> mResult = new LinkedBlockingQueue<>();
+
+        // This method expects either an event where one of the interfaces is active, or an event
+        // where one of the interface is available followed by one where one of the interfaces is
+        // active.
+        public void expectActiveTethering(String[] ifaceRegexs) {
+            TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
+            if (state == null) fail("Do not receive tethering state change broadcast");
+
+            if (isIfaceActive(ifaceRegexs, state)) return;
+
+            if (isIfaceAvailable(ifaceRegexs, state)) {
+                state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
+                if (isIfaceActive(ifaceRegexs, state)) return;
+            }
+
+            fail("Tethering is not actived, available ifaces: " + state.mAvailable.toString()
+                    + ", active ifaces: " + state.mActive.toString());
+        }
+
+        private TetherState pollAndAssertNoError(final int timeout) {
+            final TetherState state = pollTetherState(timeout);
+            assertNoErroredIfaces(state);
+            return state;
+        }
+
+        private TetherState pollTetherState(final int timeout) {
+            try {
+                return mResult.poll(timeout, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                fail("No result after " + timeout + " ms");
+                return null;
+            }
+        }
+
+        private boolean isIfaceActive(final String[] ifaceRegexs, final TetherState state) {
+            return isIfaceMatch(ifaceRegexs, state.mActive);
+        }
+
+        private boolean isIfaceAvailable(final String[] ifaceRegexs, final TetherState state) {
+            return isIfaceMatch(ifaceRegexs, state.mAvailable);
+        }
+
+        // This method requires a broadcast to have been recorded iff the timeout is non-zero.
+        public void expectNoActiveTethering(final int timeout) {
+            final TetherState state = pollAndAssertNoError(timeout);
+
+            if (state == null) {
+                if (timeout != 0) {
+                    fail("Do not receive tethering state change broadcast");
+                }
+                return;
+            }
+
+            assertNoActiveIfaces(state);
+
+            for (final TetherState ts : mResult) {
+                assertNoErroredIfaces(ts);
+
+                assertNoActiveIfaces(ts);
+            }
+        }
+
+        private void assertNoErroredIfaces(final TetherState state) {
+            if (state == null || state.mErrored == null) return;
+
+            if (state.mErrored.size() > 0) {
+                fail("Found failed tethering interfaces: " + state.mErrored.toArray());
+            }
+        }
+
+        private void assertNoActiveIfaces(final TetherState state) {
+            if (state.mActive != null && state.mActive.size() > 0) {
+                fail("Found active tethering interface: " + state.mActive.toArray());
+            }
+        }
+    }
+
+    private class OnStartTetheringCallback extends
+            ConnectivityManager.OnStartTetheringCallback {
+        @Override
+        public void onTetheringStarted() {
+            // Do nothing, TetherChangeReceiver will wait until it receives the broadcast.
+        }
+
+        @Override
+        public void onTetheringFailed() {
+            fail("startTethering fail");
+        }
+    }
+
+    private static boolean isIfaceMatch(final String[] ifaceRegexs,
+            final ArrayList<String> ifaces) {
+        if (ifaceRegexs == null) fail("ifaceRegexs should not be null");
+
+        if (ifaces == null) return false;
+
+        for (String s : ifaces) {
+            for (String regex : ifaceRegexs) {
+                if (s.matches(regex)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Test
+    public void testStartTetheringWithStateChangeBroadcast() throws Exception {
+        if (!mCM.isTetheringSupported()) return;
+
+        final String[] wifiRegexs = mCM.getTetherableWifiRegexs();
+        if (wifiRegexs.length == 0) return;
+
+        mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */);
+
+        final OnStartTetheringCallback startTetheringCallback = new OnStartTetheringCallback();
+        mCM.startTethering(ConnectivityManager.TETHERING_WIFI, true, startTetheringCallback);
+        mTetherChangeReceiver.expectActiveTethering(wifiRegexs);
+
+        mCM.stopTethering(ConnectivityManager.TETHERING_WIFI);
+        mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS);
+    }
+}
diff --git a/tests/tests/text/TEST_MAPPING b/tests/tests/text/TEST_MAPPING
index cc40b03..05e9696 100644
--- a/tests/tests/text/TEST_MAPPING
+++ b/tests/tests/text/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "CtsTextTestCases"
+    },
+    {
+      "name": "minikin_tests"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/tests/tests/view/TEST_MAPPING b/tests/tests/view/TEST_MAPPING
new file mode 100644
index 0000000..279657d
--- /dev/null
+++ b/tests/tests/view/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "minikin_tests"
+    }
+  ]
+}
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierTestWatcher.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierTestWatcher.java
index 660cb24..c921da2 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierTestWatcher.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierTestWatcher.java
@@ -144,13 +144,6 @@
         if (!TextUtils.isEmpty(deviceConfigSetting) && !deviceConfigSetting.equals("null")) {
             return deviceConfigSetting;
         }
-        // TODO(b/143585708): remove the logic when text_classifier_constants is removed
-        final String globalSetting = runShellCommand(
-                "settings get global text_classifier_constants");
-        if (!TextUtils.isEmpty(globalSetting) && globalSetting.contains(
-                "extclassifier_service_package_override")) {
-            return globalSetting.substring(globalSetting.indexOf('=') + 1);
-        }
         return DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE;
     }
 
@@ -160,14 +153,6 @@
         if (!TextUtils.isEmpty(deviceConfigSetting) && !deviceConfigSetting.equals("null")) {
             return deviceConfigSetting.toLowerCase().equals("true");
         }
-        // TODO(b/143585708): remove the logic when text_classifier_constants is removed
-        final String globalSetting = runShellCommand(
-                "settings get global text_classifier_constants");
-        if (!TextUtils.isEmpty(globalSetting) && globalSetting.contains(
-                "system_textclassifier_enabled")) {
-            return globalSetting.substring(globalSetting.indexOf('=') + 1).toLowerCase().equals(
-                    "true");
-        }
         return SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT;
     }
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 8c3b252..9b26397 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -634,7 +634,8 @@
      * Modifications to this test should be reflected in that test as necessary. See
      * http://go/modifying-webview-cts.
      */
-    public void testOnSafeBrowsingHitBackToSafety() throws Throwable {
+    // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
+    public void disabled_testOnSafeBrowsingHitBackToSafety() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
@@ -674,7 +675,8 @@
      * Modifications to this test should be reflected in that test as necessary. See
      * http://go/modifying-webview-cts.
      */
-    public void testOnSafeBrowsingHitProceed() throws Throwable {
+    // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
+    public void disabled_testOnSafeBrowsingHitProceed() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
@@ -735,22 +737,26 @@
         }
     }
 
-    public void testOnSafeBrowsingMalwareCode() throws Throwable {
+    // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
+    public void disabled_testOnSafeBrowsingMalwareCode() throws Throwable {
         testOnSafeBrowsingCode(TEST_SAFE_BROWSING_MALWARE_URL,
                 WebViewClient.SAFE_BROWSING_THREAT_MALWARE);
     }
 
-    public void testOnSafeBrowsingPhishingCode() throws Throwable {
+    // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
+    public void disabled_testOnSafeBrowsingPhishingCode() throws Throwable {
         testOnSafeBrowsingCode(TEST_SAFE_BROWSING_PHISHING_URL,
                 WebViewClient.SAFE_BROWSING_THREAT_PHISHING);
     }
 
-    public void testOnSafeBrowsingUnwantedSoftwareCode() throws Throwable {
+    // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
+    public void disabled_testOnSafeBrowsingUnwantedSoftwareCode() throws Throwable {
         testOnSafeBrowsingCode(TEST_SAFE_BROWSING_UNWANTED_SOFTWARE_URL,
                 WebViewClient.SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE);
     }
 
-    public void testOnSafeBrowsingBillingCode() throws Throwable {
+    // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
+    public void disabled_testOnSafeBrowsingBillingCode() throws Throwable {
         testOnSafeBrowsingCode(TEST_SAFE_BROWSING_BILLING_URL,
                 WebViewClient.SAFE_BROWSING_THREAT_BILLING);
     }
diff --git a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
index 74852c5..a8b3c8f 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
@@ -31,6 +31,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.OnHierarchyChangeListener;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.LinearLayout;
 import android.widget.RadioButton;
 import android.widget.RadioGroup;
@@ -412,6 +413,31 @@
         assertEquals(5, mRadioGroup.getChildCount());
     }
 
+    @UiThreadTest
+    @Test
+    public void testOnInitializeAccessibilityNodeInfo_populatesCollectionInfo() {
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+        mRadioGroup.onInitializeAccessibilityNodeInfo(info);
+
+        AccessibilityNodeInfo.CollectionInfo colInfo = info.getCollectionInfo();
+        assertNotNull(colInfo);
+        assertEquals(colInfo.getRowCount(), mRadioGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testOnInitializeAccessibilityNodeInfo_populatesCollectionItemInfo() {
+        RadioButton child = (RadioButton) mRadioGroup.getChildAt(1);
+        child.setChecked(true);
+
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+        child.onInitializeAccessibilityNodeInfo(info);
+
+        AccessibilityNodeInfo.CollectionItemInfo colItemInfo = info.getCollectionItemInfo();
+        assertEquals(colItemInfo.getRowIndex(), 1);
+        assertEquals(colItemInfo.isSelected(), true);
+    }
+
     private AttributeSet getAttributeSet(int resId) {
         XmlPullParser parser = mActivity.getResources().getLayout(resId);
         assertNotNull(parser);
diff --git a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
index 96675c3..1ca3cfa 100644
--- a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
@@ -464,6 +464,7 @@
         charsKeyNames.add(CameraCharacteristics.CONTROL_AVAILABLE_MODES.getName());
         charsKeyNames.add(CameraCharacteristics.CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE.getName());
         charsKeyNames.add(CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES.getName());
+        charsKeyNames.add(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE.getName());
         charsKeyNames.add(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES.getName());
         charsKeyNames.add(CameraCharacteristics.FLASH_INFO_AVAILABLE.getName());
         charsKeyNames.add(CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES.getName());