Merge "Don't verify insets for floating windowing mode" into tm-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 803e5f2..e55d9f6 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -101,7 +101,8 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
 
     <!-- Needed for sensor tests -->
-    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
+    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" android:maxSdkVersion="32" />
+    <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
 
     <!-- Needed for Wi-Fi Direct tests from T -->
     <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
@@ -2774,6 +2775,19 @@
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest" android:value="android.hardware.Camera#getParameters|
+                                android.hardware.Camera#setParameters|
+                                android.hardware.Camera#setDisplayOrientation|
+                                android.hardware.Camera#setPreviewCallback|
+                                android.hardware.Camera#stopPreview|
+                                android.hardware.Camera#release|
+                                android.hardware.Camera#setPreviewTexture|
+                                android.hardware.Camera#startPreview|
+                                android.hardware.Camera.Parameters#setPreviewFormat|
+                                android.hardware.Camera.Parameters#setPreviewSize|
+                                android.hardware.Camera.Parameters#getSupportedPreviewFormats|
+                                android.hardware.Camera.Parameters#getSupportedPreviewSizes|
+                                android.hardware.Camera.PreviewCallback#onPreviewFrame" />
         </activity>
 
         <activity android:name=".camera.intents.CameraIntentsActivity"
@@ -4092,6 +4106,33 @@
                 android:value="7.4.3/C-7-4" />
         </activity>
 
+        <!-- CTS Verifier Nan Precision and Bias Test Screen
+                 test category : wifi_nan
+                 test parent : PresenceTestActivity
+        -->
+        <activity
+            android:name=".presence.NanPrecisionAndBiasTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:exported="true"
+            android:label="@string/nan_precision_and_bias" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/wifi_nan" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
+            <meta-data android:name="display_mode"
+                       android:value="single_display_mode" />
+            <meta-data android:name="CddTest"
+                       android:value="7.4.2.5/H-1-1,7.4.2.5/H-1-2" />
+        </activity>
+
         <activity-alias
             android:name=".CtsVerifierActivity"
             android:label="@string/app_name"
diff --git a/apps/CtsVerifier/res/layout/nan_precision_and_bias.xml b/apps/CtsVerifier/res/layout/nan_precision_and_bias.xml
new file mode 100644
index 0000000..9e5782e
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/nan_precision_and_bias.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="vertical"
+                style="@style/RootLayoutPadding">
+    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content">
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content">
+            <TextView android:text="@string/nan_precision_and_bias_instruction"
+                      android:id="@+id/nan_precision_and_bias_instruction"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:scrollbars="vertical"/>
+            <LinearLayout android:orientation="vertical"
+                          android:layout_width="match_parent"
+                          android:layout_height="wrap_content">
+                <EditText android:id="@+id/distance_range_1m_gt"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:inputType="number"
+                          android:hint="@string/report_distance_range_1m_gt"/>
+                <EditText android:id="@+id/distance_range_3m_gt"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:inputType="number"
+                          android:hint="@string/report_distance_range_3m_gt"/>
+                <EditText android:id="@+id/distance_range_5m_gt"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:inputType="number"
+                          android:hint="@string/report_distance_range_5m_gt"/>
+                <EditText android:id="@+id/bias_meters"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:inputType="numberDecimal"
+                          android:hint="@string/report_bias_meters"/>
+                <EditText android:id="@+id/slope"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:inputType="numberDecimal"
+                          android:hint="@string/report_slope"/>
+                <EditText android:id="@+id/reference_device"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:hint="@string/report_reference_device"/>
+            </LinearLayout>
+
+            <include android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     layout="@layout/pass_fail_buttons"/>
+        </LinearLayout>
+    </ScrollView>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 44e529e..213bc55 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -6462,13 +6462,12 @@
     <string name="uwb_short_range_instruction">
         1. Take 1000 measurements with DUT being 10cm apart from the reference device
         \n2. Sort the values.
-        \n3. Report the median (500th value) in CTS-V (must be within 8cm - 12cm to pass)
+        \n3. Report the median (500th value) (must be within 8cm - 12cm to pass).
         \n4. Report the reference device used.
     </string>
     <string name="report_distance_median_cm">Report Median (cm)</string>
     <string name="report_reference_device">Report Reference Device</string>
     <string name="uwb_not_supported">Uwb is not supported on device. Finishing activity. </string>
-
     <string name="ble">BLE</string>
 
     <!-- Strings for BLE RSSI Precision Test -->
@@ -6509,4 +6508,21 @@
         \n3. Report the median (500th value); must be within [-57, -63] dBm to pass
         \n4. Report the reference device used
     </string>
+    <string name="nan_precision_and_bias_instruction">
+        1. Take 1000 ranging measurements at each of the ground truth points of 1m, 3m, and 5m. The Wifinanscan in Play Store is recommended for data collection.
+        \n2. For each point:
+        \n\t\ta. Compute and report the range (Range = 975th measurement - 25th measurement).
+        \n\t\tb. Range must be less than 2m for test to pass.
+        \n3. Using the same measurements collected in step 1, compute a least squares regression line.
+        \n4. Report the bias and slope.
+        \n5. Bias must be 0+/- 0.25m and slope must be 1+/- 0.05m for tests to pass.
+        \n6. Report reference device used. All fields must be filled before test can be passed.
+    </string>
+    <string name="report_distance_range_1m_gt">Report Measurement Range at 1m</string>
+    <string name="report_distance_range_3m_gt">Report Measurement Range at 3m</string>
+    <string name="report_distance_range_5m_gt">Report Measurement Range at 5m</string>
+    <string name="report_bias_meters">Report Bias (meters)</string>
+    <string name="report_slope">Report Slope</string>
+    <string name="nan_precision_and_bias">Nan Precision and Bias Test</string>
+    <string name="wifi_nan">WiFi NAN</string>
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
index 285aa67..256fe3a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
@@ -19,13 +19,14 @@
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;
+
 /**
  * Checks if a device supports a hardware feature needed for a test, and passes the test
  * automatically otherwise.
  */
 public class DeviceFeatureChecker {
-    /**
-     * Checks if a feature is supported.
+
+    /** Checks if a feature is supported.
      *
      * @param feature must be a string defined in PackageManager
      */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionAndBiasTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionAndBiasTestActivity.java
new file mode 100644
index 0000000..80f6985
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionAndBiasTestActivity.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.presence;
+
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.text.Editable;
+import android.util.Log;
+import android.widget.EditText;
+
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Activity for testing that NAN measurements are within the acceptable range and fits a trend line
+ * that has a bias and slope within the expected range
+ * range.
+ */
+public class NanPrecisionAndBiasTestActivity extends PassFailButtons.Activity {
+    private static final String TAG = NanPrecisionAndBiasTestActivity.class.getName();
+
+    // Report log schema
+    private static final String KEY_MEASUREMENT_RANGE_1M = "measurement_range_1m";
+    private static final String KEY_MEASUREMENT_RANGE_3M = "measurement_range_3m";
+    private static final String KEY_MEASUREMENT_RANGE_5M = "measurement_range_5m";
+    private static final String KEY_BIAS_METERS = "bias_meters";
+    private static final String KEY_SLOPE_METERS = "slope_meters";
+    private static final String KEY_REFERENCE_DEVICE = "reference_device";
+
+    // Thresholds
+    private static final int MAX_DISTANCE_RANGE_METERS = 2;
+    private static final double MIN_BIAS_METERS = -0.25;
+    private static final double MAX_BIAS_METERS = 0.25;
+    private static final double MIN_SLOPE = 0.95;
+    private static final double MAX_SLOPE = 1.05;
+
+    private EditText mMeasurementRange1mGt;
+    private EditText mMeasurementRange3mGt;
+    private EditText mMeasurementRange5mGt;
+    private EditText mBiasInput;
+    private EditText mSlopeInput;
+    private EditText mReferenceDeviceInput;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.nan_precision_and_bias);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+
+        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
+                PackageManager.FEATURE_WIFI_AWARE);
+
+        mMeasurementRange1mGt = (EditText) findViewById(R.id.distance_range_1m_gt);
+        mMeasurementRange3mGt = (EditText) findViewById(R.id.distance_range_3m_gt);
+        mMeasurementRange5mGt = (EditText) findViewById(R.id.distance_range_5m_gt);
+        mBiasInput = (EditText) findViewById(R.id.bias_meters);
+        mSlopeInput = (EditText) findViewById(R.id.slope);
+        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
+
+        mMeasurementRange1mGt.addTextChangedListener(
+                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
+        mMeasurementRange3mGt.addTextChangedListener(
+                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
+        mMeasurementRange5mGt.addTextChangedListener(
+                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
+        mBiasInput.addTextChangedListener(
+                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
+        mSlopeInput.addTextChangedListener(
+                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
+        mReferenceDeviceInput.addTextChangedListener(
+                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
+    }
+
+    private void checkTestInputs() {
+        getPassButton().setEnabled(checkMeasurementRangeInput()
+                && checkBiasInput() && checkSlopeInput()
+                && checkReferenceDeviceInput());
+    }
+
+    private boolean checkMeasurementRangeInput() {
+        String measurementRangeInput1mGt = mMeasurementRange1mGt.getText().toString();
+        String measurementRangeInput3mGt = mMeasurementRange3mGt.getText().toString();
+        String measurementRangeInput5mGt = mMeasurementRange1mGt.getText().toString();
+        List<String> measurementRangeList = Arrays.asList(measurementRangeInput1mGt,
+                measurementRangeInput3mGt, measurementRangeInput5mGt);
+
+        for (String input : measurementRangeList) {
+            if (input.isEmpty()) {
+                // Distance range must be inputted for all fields so fail early otherwise
+                return false;
+            }
+            int distanceRange = Integer.parseInt(input);
+            if (distanceRange > MAX_DISTANCE_RANGE_METERS) {
+                // All inputs must be in acceptable range so fail early otherwise
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean checkBiasInput() {
+        String biasInput = mBiasInput.getText().toString();
+
+        if (!biasInput.isEmpty()) {
+            double bias = Double.parseDouble(biasInput);
+            // Bias must be inputted and within acceptable range before test can be passed.
+            return bias >= MIN_BIAS_METERS && bias <= MAX_BIAS_METERS;
+        }
+        return false;
+    }
+
+    private boolean checkSlopeInput() {
+        String slopeInput = mSlopeInput.getText().toString();
+
+        if (!slopeInput.isEmpty()) {
+            double slope = Double.parseDouble(slopeInput);
+            // Slope must be inputted and within acceptable range before test can be passed.
+            return slope >= MIN_SLOPE && slope <= MAX_SLOPE;
+        }
+        return false;
+    }
+
+    private boolean checkReferenceDeviceInput() {
+        // Reference device used must be inputted before test can be passed.
+        return !mReferenceDeviceInput.getText().toString().isEmpty();
+    }
+
+    @Override
+    public void recordTestResults() {
+        String measurementRange1mGt = mMeasurementRange1mGt.getText().toString();
+        String measurementRange3mGt = mMeasurementRange3mGt.getText().toString();
+        String measurementRange5mGt = mMeasurementRange5mGt.getText().toString();
+        String bias = mBiasInput.getText().toString();
+        String slope = mSlopeInput.getText().toString();
+        String referenceDevice = mReferenceDeviceInput.getText().toString();
+
+        if (!measurementRange1mGt.isEmpty()) {
+            Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt);
+            getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M,
+                    Integer.parseInt(measurementRange1mGt),
+                    ResultType.NEUTRAL, ResultUnit.NONE);
+        }
+
+        if (!measurementRange3mGt.isEmpty()) {
+            Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt);
+            getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M,
+                    Integer.parseInt(measurementRange1mGt),
+                    ResultType.NEUTRAL, ResultUnit.NONE);
+        }
+
+        if (!measurementRange5mGt.isEmpty()) {
+            Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt);
+            getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M,
+                    Integer.parseInt(measurementRange1mGt),
+                    ResultType.NEUTRAL, ResultUnit.NONE);
+        }
+
+        if (!bias.isEmpty()) {
+            Log.i(TAG, "NAN bias: " + bias);
+            getReportLog().addValue(KEY_BIAS_METERS, Double.parseDouble(bias),
+                    ResultType.NEUTRAL, ResultUnit.NONE);
+        }
+
+        if (!slope.isEmpty()) {
+            Log.i(TAG, "NAN slope: " + slope);
+            getReportLog().addValue(KEY_SLOPE_METERS, Double.parseDouble(slope),
+                    ResultType.NEUTRAL, ResultUnit.NONE);
+        }
+
+        if (!referenceDevice.isEmpty()) {
+            Log.i(TAG, "NAN Reference Device: " + referenceDevice);
+            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
+                    ResultType.NEUTRAL, ResultUnit.NONE);
+        }
+        getReportLog().submit();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
index a9ef722..2d67640 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 package com.android.cts.verifier.presence;
+
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.text.Editable;
 import android.util.Log;
 import android.widget.EditText;
+
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
+
 /**
  * Activity for testing that UWB distance and angle of arrival measurements are within the right
  * range.
@@ -36,17 +39,21 @@
     // Thresholds
     private static final int MAX_DISTANCE_RANGE_CM = 10;
     private static final int MAX_ANGLE_OF_ARRIVAL_RANGE_DEGREES = 5;
+
     private EditText mDistanceRangeInput;
     private EditText mAoaRangeInput;
     private EditText mReferenceDeviceInput;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.uwb_precision);
         setPassFailButtonClickListeners();
         getPassButton().setEnabled(false);
+
         DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
                 PackageManager.FEATURE_UWB);
+
         mDistanceRangeInput = (EditText) findViewById(R.id.distance_range_cm);
         mAoaRangeInput = (EditText) findViewById(R.id.aoa_range_degrees);
         mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
@@ -57,33 +64,38 @@
         mReferenceDeviceInput.addTextChangedListener(
                 InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
     }
+
     private void checkTestInputs() {
         getPassButton().setEnabled(
                 checkDistanceRangeInput() && checkAoaRangeInput() && checkReferenceDeviceInput());
     }
+
     private boolean checkDistanceRangeInput() {
         String distanceRangeInput = mDistanceRangeInput.getText().toString();
         if (!distanceRangeInput.isEmpty()) {
             int distanceRange = Integer.parseInt(distanceRangeInput);
             // Distance range must be inputted and within acceptable range before test can be
             // passed.
-            return distanceRange < MAX_DISTANCE_RANGE_CM;
+            return distanceRange <= MAX_DISTANCE_RANGE_CM;
         }
         return false;
     }
+
     private boolean checkAoaRangeInput() {
         String aoaRangeInput = mAoaRangeInput.getText().toString();
         if (!aoaRangeInput.isEmpty()) {
             int aoaRange = Integer.parseInt(aoaRangeInput);
             // Aoa range must be within acceptable range before test can be passed.
-            return aoaRange < MAX_ANGLE_OF_ARRIVAL_RANGE_DEGREES;
+            return aoaRange <= MAX_ANGLE_OF_ARRIVAL_RANGE_DEGREES;
         }
         return true;
     }
+
     private boolean checkReferenceDeviceInput() {
         // Reference device must be inputted before test can be passed.
         return !mReferenceDeviceInput.getText().toString().isEmpty();
     }
+
     @Override
     public void recordTestResults() {
         String distanceRange = mDistanceRangeInput.getText().toString();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
index ef6ccc8..8f5e8d8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 package com.android.cts.verifier.presence;
+
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.text.Editable;
 import android.util.Log;
 import android.widget.EditText;
+
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
+
 /**
  * Activity for testing that UWB distance measurements are within the acceptable median.
  */
@@ -36,14 +39,17 @@
     private static final int MAX_MEDIAN = 12;
     private EditText mMedianInput;
     private EditText mReferenceDeviceInput;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.uwb_short_range);
         setPassFailButtonClickListeners();
         getPassButton().setEnabled(false);
+
         DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
                 PackageManager.FEATURE_UWB);
+
         mMedianInput = (EditText) findViewById(R.id.distance_median_cm);
         mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
         mMedianInput.addTextChangedListener(
@@ -51,9 +57,11 @@
         mReferenceDeviceInput.addTextChangedListener(
                 InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
     }
+
     private void checkTestInputs() {
         getPassButton().setEnabled(checkMedianInput() && checkReferenceDeviceInput());
     }
+
     private boolean checkMedianInput() {
         String medianInput = mMedianInput.getText().toString();
         if (!medianInput.isEmpty()) {
@@ -62,9 +70,11 @@
         }
         return false;
     }
+
     private boolean checkReferenceDeviceInput() {
         return !mReferenceDeviceInput.getText().toString().isEmpty();
     }
+
     @Override
     public void recordTestResults() {
         String medianInput = mMedianInput.getText().toString();
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/PreferentialNetworkService.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/PreferentialNetworkService.java
index 707e1de..0f12974 100644
--- a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/PreferentialNetworkService.java
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/PreferentialNetworkService.java
@@ -17,16 +17,17 @@
 package com.android.bedstead.harrier.policies;
 
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
-import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_PROFILE;
 
 import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
 
 /**
  * Policy for testing preferential network service.
+ * Behavior is undefined when applied by profile owner on full users.
  * See {@code DevicePolicyManager#setPreferentialNetworkServiceEnabled(boolean)} for more detail.
  */
-@EnterprisePolicy(dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER
+@EnterprisePolicy(dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER_PROFILE
         | APPLIES_TO_OWN_USER)
 public final class PreferentialNetworkService {
 }
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/ScreenCaptureDisabled.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/ScreenCaptureDisabled.java
index 8cdb1b0..045b625 100644
--- a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/ScreenCaptureDisabled.java
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/ScreenCaptureDisabled.java
@@ -19,6 +19,7 @@
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PARENT_INSTANCE_OF_COPE_PROFILE_OWNER_PROFILE;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_GLOBALLY;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
 
 import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
@@ -29,7 +30,8 @@
  * <p>Users of this policy are
  * {@code DevicePolicyManager#setScreenCaptureDisabled(ComponentName, boolean)}.
  */
-@EnterprisePolicy(dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER
-        | APPLIED_BY_PARENT_INSTANCE_OF_COPE_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER)
+@EnterprisePolicy(dpc = {
+        APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PARENT_INSTANCE_OF_COPE_PROFILE_OWNER_PROFILE
+                | APPLIES_GLOBALLY, APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
 public final class ScreenCaptureDisabled {
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
index ce73f43..687a74c 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
@@ -17,12 +17,15 @@
 package com.android.bedstead.nene.devicepolicy;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.os.Build.VERSION_CODES.R;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
 
 import static com.android.bedstead.nene.permissions.CommonPermissions.MANAGE_PROFILE_AND_DEVICE_OWNERS;
 import static com.android.compatibility.common.util.enterprise.DeviceAdminReceiverUtils.ACTION_DISABLE_SELF;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -60,6 +63,31 @@
         super(user, pkg, componentName);
     }
 
+    /** Returns whether the current profile is organization owned. */
+    @TargetApi(R)
+    public boolean isOrganizationOwned() {
+        if (!Versions.meetsMinimumSdkVersionRequirement(R)) {
+            return false;
+        }
+
+        DevicePolicyManager devicePolicyManager =
+                TestApis.context().androidContextAsUser(mUser).getSystemService(
+                        DevicePolicyManager.class);
+        return devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile();
+    }
+
+    /** Sets whether the current profile is organization owned. */
+    @TargetApi(TIRAMISU)
+    public void setIsOrganizationOwned(boolean isOrganizationOwned) {
+        Versions.requireMinimumVersion(TIRAMISU);
+
+        DevicePolicyManager devicePolicyManager =
+                TestApis.context().androidContextAsUser(mUser).getSystemService(
+                        DevicePolicyManager.class);
+        devicePolicyManager.setProfileOwnerOnOrganizationOwnedDevice(mComponentName,
+                isOrganizationOwned);
+    }
+
     @Override
     public void remove() {
         if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java
index 9598e70..f2f460c 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java
@@ -16,15 +16,21 @@
 
 package com.android.bedstead.nene.devicepolicy;
 
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.android.bedstead.nene.permissions.CommonPermissions.MANAGE_PROFILE_AND_DEVICE_OWNERS;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ComponentName;
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.EnsureHasPermission;
 import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
 import com.android.bedstead.harrier.annotations.RequireRunNotOnSecondaryUser;
 import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile;
+import com.android.bedstead.harrier.annotations.RequireSdkVersion;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasProfileOwner;
 import com.android.bedstead.nene.TestApis;
@@ -42,7 +48,8 @@
 @RunWith(BedsteadJUnit4.class)
 public class ProfileOwnerTest {
 
-    @ClassRule @Rule
+    @ClassRule
+    @Rule
     public static final DeviceState sDeviceState = new DeviceState();
 
     private static final ComponentName DPC_COMPONENT_NAME = RemoteDpc.DPC_COMPONENT_NAME;
@@ -127,4 +134,31 @@
 
         assertThat(TestApis.devicePolicy().getProfileOwner()).isNull();
     }
+
+    @Test
+    @RequireSdkVersion(min = TIRAMISU)
+    @RequireRunOnWorkProfile
+    @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public void setIsOrganizationOwned_becomesOrganizationOwned() {
+        ProfileOwner profileOwner = (ProfileOwner) sDeviceState.profileOwner(
+                sDeviceState.workProfile()).devicePolicyController();
+
+        profileOwner.setIsOrganizationOwned(true);
+
+        assertThat(profileOwner.isOrganizationOwned()).isTrue();
+    }
+
+    @Test
+    @RequireSdkVersion(min = TIRAMISU)
+    @RequireRunOnWorkProfile
+    @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public void unsetIsOrganizationOwned_becomesNotOrganizationOwned() {
+        ProfileOwner profileOwner = (ProfileOwner) sDeviceState.profileOwner(
+                sDeviceState.workProfile()).devicePolicyController();
+        profileOwner.setIsOrganizationOwned(true);
+
+        profileOwner.setIsOrganizationOwned(false);
+
+        assertThat(profileOwner.isOrganizationOwned()).isFalse();
+    }
 }
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index 0434258..d0384b1 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -761,6 +761,7 @@
                 .filter(file -> doesFileExist(file, testInfo.getDevice()))
                 // GmsCore should not contribute to *classpath.
                 .filter(file -> !file.contains("GmsCore"))
+                .filter(file -> !file.contains("com.google.android.gms"))
                 .collect(ImmutableList.toImmutableList());
 
         final ImmutableSetMultimap.Builder<String, String> jarsToClasses =
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index 62e2180..b9ef7ad 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -20,7 +20,6 @@
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.util.ApiLevelUtil;
-
 import com.android.tradefed.device.DeviceNotAvailableException;
 
 import com.google.common.collect.ImmutableSet;
@@ -129,6 +128,30 @@
         runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testEject");
     }
 
+    public void testScopeStorageAtInitLocationRootWithDot_blockFromTree() throws Exception {
+        if (isAtLeastT()) {
+            // From BUILD.VERSION_CODES.S, scope storage is enabled in default
+            runDeviceTests(CLIENT_PKG, ".DocumentsClientTest",
+                    "testScopeStorageAtInitLocationRootWithDot_blockFromTree");
+        }
+    }
+
+    public void testScopeStorageAtInitLocationAndroidData_blockFromTree() throws Exception {
+        if (isAtLeastT()) {
+            // From BUILD.VERSION_CODES.S, scope storage is enabled in default
+            runDeviceTests(CLIENT_PKG, ".DocumentsClientTest",
+                    "testScopeStorageAtInitLocationAndroidData_blockFromTree");
+        }
+    }
+
+    public void testScopeStorageAtInitLocationAndroidObb_blockFromTree() throws Exception {
+        if (isAtLeastT()) {
+            // From BUILD.VERSION_CODES.S, scope storage is enabled in default
+            runDeviceTests(CLIENT_PKG, ".DocumentsClientTest",
+                    "testScopeStorageAtInitLocationAndroidObb_blockFromTree");
+        }
+    }
+
     public void testRestrictStorageAccessFrameworkEnabled_blockFromTree() throws Exception {
         if (isAtLeastR() && isSupportedHardware()) {
             runDeviceCompatTestReported(CLIENT_PKG, ".DocumentsClientTest",
@@ -177,6 +200,14 @@
         }
     }
 
+    private boolean isAtLeastT() {
+        try {
+            return ApiLevelUtil.isAfter(getDevice(), 32 /* BUILD.VERSION_CODES.S_V2 */);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
     private boolean isSupportedHardware() {
         try {
             if (getDevice().hasFeature("feature:android.hardware.type.television")
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
index 5370a12..616ce26 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -672,6 +672,65 @@
         assertInstallFromBuildFails("v3-por_Z_1_2-default-caps-sharedUid-companion.apk");
     }
 
+    public void testInstallV3WithRestoredCapabilityInSharedUserId() throws Exception {
+        // A sharedUserId contains the shared signing lineage for all packages in the UID; this
+        // shared lineage contain the full signing history for all packages along with the merged
+        // capabilities for each signer shared between the packages. This test verifies if one
+        // package revokes a capability from a previous signer, but subsequently restores that
+        // capability, then since all packages have granted the capability, it is restored to the
+        // previous signer in the shared lineage.
+
+        // Install a package with the SHARED_USER_ID capability revoked for the original signer
+        // in the lineage; verify that a package signed with only the original signer cannot join
+        // the sharedUserId.
+        assertInstallFromBuildSucceeds(
+                "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
+        assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
+        assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
+
+        // Update the package that revoked the SHARED_USER_ID with an updated lineage that restores
+        // this capability to the original signer; verify the package signed with the original
+        // signing key can now join the sharedUserId since all existing packages in the UID grant
+        // this capability to the original signer.
+        assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
+        assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
+    }
+
+    public void testInstallV3WithRevokedCapabilityInSharedUserId() throws Exception {
+        // While a capability can be restored to a common signer in the shared signing lineage, if
+        // one package has revoked a capability from a common signer and another package is
+        // installed / updated which restores the capability to that signer, the revocation of
+        // the capability by the existing package should take precedence. A capability can only
+        // be restored to a common signer if all packages in the sharedUserId have granted this
+        // capability to the signer.
+
+        // Install a package with the SHARED_USER_ID capability revoked from the original signer,
+        // then install another package in the sharedUserId that grants this capability to the
+        // original signer. Since a package exists in the sharedUserId that has revoked this
+        // capability, another package signed with this capability shouldn't be able to join the
+        // sharedUserId.
+        assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
+        assertInstallFromBuildSucceeds(
+                "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
+        assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
+
+        // Install the same package that grants the SHARED_USER_ID capability to the original
+        // signer; when iterating over the existing packages in the packages in the sharedUserId,
+        // the original version of this package should be skipped since the lineage from the
+        // updated package is used when merging with the shared lineage.
+        assertInstallFromBuildSucceeds(
+                "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
+        assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
+
+        // Install another package that has granted the SHARED_USER_ID to the original signer; this
+        // should trigger another merge with all packages in the sharedUserId. Since one still
+        // remains that revokes the capability, the capability should be revoked in the shared
+        // lineage.
+        assertInstallFromBuildSucceeds(
+                "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion3.apk");
+        assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
+    }
+
     public void testInstallV3UpdateAfterRotation() throws Exception {
         // This test performs an end to end verification of the update of an app with a rotated
         // key. The app under test exports a bound service that performs its own PackageManager key
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
index 392f525..cd66d3e 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
@@ -238,6 +238,13 @@
         }
     }
 
+    @Test
+    public void testNoExternalAppStorage() throws Exception {
+        for (int user : mUsers) {
+            runDeviceTests(PKG_NO_APP_STORAGE, CLASS_NO_APP_STORAGE, "testNoExternalStorage", user);
+        }
+    }
+
     public void waitForIdle() throws Exception {
         // Try getting all pending events flushed out
         for (int i = 0; i < 4; i++) {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 0df4795..9e12ad0 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -26,7 +26,6 @@
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
-import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
@@ -488,7 +487,7 @@
 
         mDevice.waitForIdle();
 
-        // save button is enabled for for the storage root
+        // save button is enabled for the storage root
         assertTrue(findSaveButton().isEnabled());
 
         // We should always have Android directory available
@@ -530,6 +529,36 @@
         assertTrue(findSaveButton().isEnabled());
     }
 
+    public void testScopeStorageAtInitLocationRootWithDot_blockFromTree() throws Exception {
+        if (!supportedHardware()) return;
+
+        launchOpenDocumentTreeAtInitialLocation(STORAGE_AUTHORITY, "primary:.");
+
+        // save button is disabled for the directory
+        assertFalse(findSaveButton().isEnabled());
+
+        // The Android directory is available
+        assertTrue(findDocument("Android").exists());
+    }
+
+    public void testScopeStorageAtInitLocationAndroidData_blockFromTree() throws Exception {
+        if (!supportedHardware()) return;
+
+        launchOpenDocumentTreeAtInitialLocation(STORAGE_AUTHORITY, "primary:Android/data");
+
+        // save button is disabled for the directory
+        assertFalse(findSaveButton().isEnabled());
+    }
+
+    public void testScopeStorageAtInitLocationAndroidObb_blockFromTree() throws Exception {
+        if (!supportedHardware()) return;
+
+        launchOpenDocumentTreeAtInitialLocation(STORAGE_AUTHORITY, "primary:Android/obb");
+
+        // save button is disabled for the directory
+        assertFalse(findSaveButton().isEnabled());
+    }
+
     public void testGetContent_rootsShowing() throws Exception {
         if (!supportedHardware()) return;
 
@@ -799,15 +828,7 @@
     public void testOpenDocumentTreeAtInitialLocation() throws Exception {
         if (!supportedHardware()) return;
 
-        // Clear DocsUI's storage to avoid it opening stored last location.
-        clearDocumentsUi();
-
-        final Uri docUri = DocumentsContract.buildDocumentUri(PROVIDER_PACKAGE, "doc:dir2");
-        final Intent intent = new Intent();
-        intent.setAction(Intent.ACTION_OPEN_DOCUMENT_TREE);
-        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, docUri);
-        mActivity.startActivityForResult(intent, REQUEST_CODE);
-        mDevice.waitForIdle();
+        launchOpenDocumentTreeAtInitialLocation(PROVIDER_PACKAGE, "doc:dir2");
 
         assertTrue(findDocument("FILE4").exists());
     }
@@ -970,6 +991,19 @@
                 context.checkCallingOrSelfUriPermission(targetUri, permissionFlag));
     }
 
+    private void launchOpenDocumentTreeAtInitialLocation(@NonNull String authority,
+            @NonNull String docId) throws Exception {
+        // Clear DocsUI's storage to avoid it opening stored last location.
+        clearDocumentsUi();
+
+        final Uri initUri = DocumentsContract.buildDocumentUri(authority, docId);
+        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
+        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initUri);
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+        mDevice.waitForIdle();
+    }
+
     private Uri assertCreateDocumentSuccess(@Nullable Uri initUri, @NonNull String displayName,
             @NonNull String mimeType) throws Exception {
         // Clear DocsUI's storage to avoid it opening stored last location.
diff --git a/hostsidetests/appsecurity/test-apps/NoDataStorageApp/src/com/android/cts/noappstorage/NoAppDataStorageTest.java b/hostsidetests/appsecurity/test-apps/NoDataStorageApp/src/com/android/cts/noappstorage/NoAppDataStorageTest.java
index e69ef3e..b599b2c 100644
--- a/hostsidetests/appsecurity/test-apps/NoDataStorageApp/src/com/android/cts/noappstorage/NoAppDataStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/NoDataStorageApp/src/com/android/cts/noappstorage/NoAppDataStorageTest.java
@@ -21,6 +21,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
+import android.os.Environment;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -54,6 +55,26 @@
         assertDirDoesNotExist(mDeContext.getCodeCacheDir());
     }
 
+    @Test
+    public void testNoExternalStorage() throws Exception {
+        final String[] types = new String[] {
+                Environment.DIRECTORY_MUSIC,
+                Environment.DIRECTORY_PODCASTS,
+                Environment.DIRECTORY_RINGTONES,
+                Environment.DIRECTORY_ALARMS,
+                Environment.DIRECTORY_NOTIFICATIONS,
+                Environment.DIRECTORY_PICTURES,
+                Environment.DIRECTORY_MOVIES,
+                Environment.DIRECTORY_DOWNLOADS,
+                Environment.DIRECTORY_DCIM,
+                Environment.DIRECTORY_DOCUMENTS
+        };
+        for (String type : types) {
+            File dir = mCeContext.getExternalFilesDir(type);
+            assertThat(dir).isNull();
+        }
+    }
+
     private void assertDirDoesNotExist(File dir) throws Exception {
         assertThat(dir.exists()).isFalse();
         assertThat(dir.mkdirs()).isFalse();
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/Android.bp b/hostsidetests/appsecurity/test-apps/tinyapp/Android.bp
index 1c98103..df32835 100644
--- a/hostsidetests/appsecurity/test-apps/tinyapp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/Android.bp
@@ -286,6 +286,24 @@
     sdk_version: "current",
 }
 
+// This is the third companion package signed using the V3 signature scheme
+// with a rotated key and part of a sharedUid. The capabilities of this lineage
+// grant access to the previous key in the lineage to join the sharedUid.
+android_test_helper_app {
+    name: "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion3",
+    manifest: "AndroidManifest-companion3-shareduid.xml",
+    certificate: ":ec-p256_2",
+    additional_certificates: [":ec-p256"],
+    lineage: ":ec-p256-por_1_2-default-caps",
+    srcs: ["src/**/*.java"],
+    // resource_dirs is the default value: ["res"]
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    sdk_version: "current",
+}
+
 // This is a version of the test package that declares a signature permission.
 // The lineage used to sign this test package does not trust the first signing
 // key but grants default capabilities to the second signing key.
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest-companion3-shareduid.xml b/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest-companion3-shareduid.xml
new file mode 100644
index 0000000..589ad60
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest-companion3-shareduid.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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.appsecurity.cts.tinyapp_companion3"
+     android:sharedUserId="android.appsecurity.cts.tinyapp.shareduser"
+     android:versionCode="10"
+     android:versionName="1.0"
+     android:targetSandboxVersion="2">
+    <application android:label="@string/app_name">
+        <activity android:name=".MainActivity"
+             android:label="@string/app_name"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
index 4fc80f7..f3cb6ce 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.deviceowner;
 
+import static android.os.Process.BLUETOOTH_UID;
+
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.bluetooth.BluetoothAdapter;
@@ -40,9 +42,8 @@
     private static final int POLL_TIME_MS = 400;          // ms to poll BT state
     private static final int CHECK_WAIT_TIME_MS = 1_000;  // ms to wait before enable/disable
     private static final int COMPONENT_STATE_TIMEOUT_MS = 10_000;
-    private static final ComponentName OPP_LAUNCHER_COMPONENT = new ComponentName(
-            "com.android.bluetooth", "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
-
+    private static final String OPP_LAUNCHER_CLASS =
+            "com.android.bluetooth.opp.BluetoothOppLauncherActivity";
     private BluetoothAdapter mBluetoothAdapter;
     private PackageManager mPackageManager;
 
@@ -131,28 +132,38 @@
             return;
         }
 
+        String bluetoothPackageName = mContext.getPackageManager()
+                .getPackagesForUid(BLUETOOTH_UID)[0];
+
+        ComponentName oppLauncherComponent = new ComponentName(
+                bluetoothPackageName, OPP_LAUNCHER_CLASS);
+
         // First verify DISALLOW_BLUETOOTH.
-        testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH);
+        testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH,
+                oppLauncherComponent);
+
         // Verify DISALLOW_BLUETOOTH_SHARING which leaves bluetooth workable but the sharing
         // component should be disabled.
-        testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH_SHARING);
+        testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH_SHARING,
+                oppLauncherComponent);
     }
 
     /** Verifies that a given restriction disables the bluetooth sharing component. */
-    private void testOppDisabledWhenRestrictionSet(String restriction) {
+    private void testOppDisabledWhenRestrictionSet(String restriction,
+            ComponentName oppLauncherComponent) {
         // Add the user restriction.
         addUserRestriction(restriction);
 
         // The BluetoothOppLauncherActivity's component should be disabled.
         assertComponentStateAfterTimeout(
-                OPP_LAUNCHER_COMPONENT, PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+                oppLauncherComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
 
         // Remove the user restriction.
         clearUserRestriction(restriction);
 
         // The BluetoothOppLauncherActivity's component should be in the default state.
         assertComponentStateAfterTimeout(
-                OPP_LAUNCHER_COMPONENT, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+                oppLauncherComponent, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
     }
 
     /** Helper to turn BT off.
@@ -218,7 +229,8 @@
         while (SystemClock.elapsedRealtime() < timeout) {
             state = mPackageManager.getComponentEnabledSetting(component);
             if (expectedState == state) {
-                // Success
+                // Success, waiting for component to be fully turned on/off
+                sleep(CHECK_WAIT_TIME_MS);
                 return;
             }
             sleep(POLL_TIME_MS);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
index 3a8eef6..32313a8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
@@ -525,7 +525,7 @@
 
         // Test managed profile. This should not be disabled when screen capture is disabled on
         // the parent by the profile owner of an organization-owned device.
-        takeScreenCaptureAsUser(mUserId, "testScreenCapturePossible");
+        takeScreenCaptureAsUser(mUserId, testMethodName);
     }
 
     private void assertHasNoUser(int userId) throws DeviceNotAvailableException {
diff --git a/hostsidetests/incident/AndroidTest.xml b/hostsidetests/incident/AndroidTest.xml
index 57fd89d..727277d 100644
--- a/hostsidetests/incident/AndroidTest.xml
+++ b/hostsidetests/incident/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
         <option name="user-type" value="system" />
     </target_preparer>
diff --git a/hostsidetests/jvmti/allocation-tracking/Android.bp b/hostsidetests/jvmti/allocation-tracking/Android.bp
index 07956a3..208b102 100644
--- a/hostsidetests/jvmti/allocation-tracking/Android.bp
+++ b/hostsidetests/jvmti/allocation-tracking/Android.bp
@@ -27,4 +27,8 @@
     test_options: {
         unit_test: false,
     },
+    data: [
+        ":CtsJvmtiTrackingDeviceApp",
+    ],
+    per_testcase_directory: true,
 }
\ No newline at end of file
diff --git a/hostsidetests/media/bitstreams/Android.bp b/hostsidetests/media/bitstreams/Android.bp
index 30bbb69..f7bf1a3 100644
--- a/hostsidetests/media/bitstreams/Android.bp
+++ b/hostsidetests/media/bitstreams/Android.bp
@@ -36,4 +36,8 @@
     ],
     java_resources: ["DynamicConfig.xml"],
     required: ["cts-dynamic-config"],
+    data: [
+        ":CtsMediaBitstreamsDeviceSideTestApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/numberblocking/Android.bp b/hostsidetests/numberblocking/Android.bp
index 67ce71c..aaad013 100644
--- a/hostsidetests/numberblocking/Android.bp
+++ b/hostsidetests/numberblocking/Android.bp
@@ -29,4 +29,8 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    data: [
+        ":CtsHostsideNumberBlockingAppTest",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/os/Android.bp b/hostsidetests/os/Android.bp
index f60a789..7c539c2 100644
--- a/hostsidetests/os/Android.bp
+++ b/hostsidetests/os/Android.bp
@@ -35,4 +35,14 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsStaticSharedLibProviderApp1",
+        ":CtsStaticSharedLibProviderApp2",
+        ":CtsDeviceOsTestApp",
+        ":CtsHostProcfsTestApp",
+        ":CtsInattentiveSleepTestApp",
+        ":CtsHostEnvironmentTestApp",
+        ":CtsStaticSharedLibTestApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/packagemanager/dynamicmime/Android.bp b/hostsidetests/packagemanager/dynamicmime/Android.bp
index 39247de..b9c4a73 100644
--- a/hostsidetests/packagemanager/dynamicmime/Android.bp
+++ b/hostsidetests/packagemanager/dynamicmime/Android.bp
@@ -30,4 +30,13 @@
         "compatibility-host-util",
         "truth-prebuilt",
     ],
+    data: [
+        ":CtsDynamicMimeUpdateAppFirstGroup",
+        ":CtsDynamicMimeUpdateAppSecondGroup",
+        ":CtsDynamicMimeUpdateAppBothGroups",
+        ":CtsDynamicMimePreferredApp",
+        ":CtsDynamicMimeHelperApp",
+        ":CtsDynamicMimeTestApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/packagemanager/installedloadingprogess/Android.bp b/hostsidetests/packagemanager/installedloadingprogess/Android.bp
index 1dff1a3..a81820a 100644
--- a/hostsidetests/packagemanager/installedloadingprogess/Android.bp
+++ b/hostsidetests/packagemanager/installedloadingprogess/Android.bp
@@ -31,4 +31,9 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsInstalledLoadingProgressDeviceTests",
+        ":CtsInstalledLoadingProgressTestsRegisterApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/packagemanager/multiuser/Android.bp b/hostsidetests/packagemanager/multiuser/Android.bp
index 855700f..2ed3804 100644
--- a/hostsidetests/packagemanager/multiuser/Android.bp
+++ b/hostsidetests/packagemanager/multiuser/Android.bp
@@ -33,4 +33,8 @@
     required: [
         "CtsPackageManagerMultiUserEmptyTestApp",
     ],
+    data: [
+        ":CtsPackageManagerMultiUserTestApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/seccomp/Android.bp b/hostsidetests/seccomp/Android.bp
index d1f8121..9e707df 100644
--- a/hostsidetests/seccomp/Android.bp
+++ b/hostsidetests/seccomp/Android.bp
@@ -29,4 +29,8 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    data: [
+        ":CtsSeccompDeviceApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp
index 7770ebd..323d5b7 100644
--- a/hostsidetests/securitybulletin/Android.bp
+++ b/hostsidetests/securitybulletin/Android.bp
@@ -34,6 +34,12 @@
         "sts-host-util",
         "tradefed",
     ],
+    data: [
+        ":CtsHostLaunchAnyWhereApp",
+        ":MainlineModuleDetector",
+        ":hotspot",
+    ],
+    per_testcase_directory: true,
 }
 
 cc_defaults {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
new file mode 100644
index 0000000..d59fce4
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class Bug_183411210 extends SecurityTestCase {
+    private static final String TEST_PKG = "android.security.cts.BUG_183411210";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "BUG-183411210.apk";
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        assumeTrue("not an Automotive device",
+            getDevice().hasFeature("feature:android.hardware.type.automotive"));
+        uninstallPackage(getDevice(), TEST_PKG);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 183411210)
+    public void testRunDeviceTestsPassesFull() throws Exception {
+        installPackage(TEST_APP);
+        // Grant permission to draw overlays.
+        getDevice().executeShellCommand(
+                "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW");
+        assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testTapjacking"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-183411210/Android.bp
new file mode 100644
index 0000000..2648a19
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "BUG-183411210",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-183411210/AndroidManifest.xml
new file mode 100644
index 0000000..30598a9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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.security.cts.BUG_183411210"
+          minSdkVersion="29">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application android:theme="@style/Theme.AppCompat.Light">
+        <uses-library android:name="android.test.runner" />
+        <service android:name=".OverlayService"
+                 android:enabled="true"
+                 android:exported="false" />
+
+        <activity
+            android:name=".MainActivity"
+            android:label="ST (Permission)"
+            android:exported="true"
+            android:taskAffinity="android.security.cts.BUG_183411210.MainActivity">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.BUG_183411210" />
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/BUG-183411210/res/layout/activity_main.xml
new file mode 100644
index 0000000..c23b709
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/res/layout/activity_main.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="left"
+    tools:context=".MainActivity" >
+
+    <LinearLayout
+        android:id="@+id/linearLayout1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/seekShowTimes"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="53dp"
+        android:orientation="horizontal" >
+
+        <Button
+            android:id="@+id/btnStart"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Start" />
+
+    </LinearLayout>
+
+</RelativeLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/BUG-183411210/res/values/strings.xml
new file mode 100644
index 0000000..3db77b0
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <string name="tapjacking_text">BUG_183411210 overlay text</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/Constants.java b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/Constants.java
new file mode 100644
index 0000000..9445d51
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/Constants.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_183411210;
+
+final class Constants {
+
+    public static final String LOG_TAG = "BUG-183411210";
+    public static final String TEST_APP_PACKAGE = Constants.class.getPackage().getName();
+
+    public static final String ACTION_START_TAPJACKING = "BUG_183411210.start_tapjacking";
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/DeviceTest.java
new file mode 100644
index 0000000..08b68e2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/DeviceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_183411210;
+
+import static android.security.cts.BUG_183411210.Constants.LOG_TAG;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Basic sample for unbundled UiAutomator. */
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    private static final long WAIT_FOR_UI_TIMEOUT = 20_000;
+
+    private Context mContext;
+    private UiDevice mDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        Log.d(LOG_TAG, "startMainActivityFromHomeScreen()");
+
+        mContext = getApplicationContext();
+
+        // If the permission is not granted, the app will not be able to show an overlay dialog.
+        // This is required for the test below.
+        // NOTE: The permission is granted by the HostJUnit4Test implementation and should not fail.
+        assertEquals("Permission SYSTEM_ALERT_WINDOW not granted!",
+                mContext.checkSelfPermission("android.permission.SYSTEM_ALERT_WINDOW"),
+                PackageManager.PERMISSION_GRANTED);
+
+        // Initialize UiDevice instance
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        if (!mDevice.isScreenOn()) {
+            mDevice.wakeUp();
+        }
+        mDevice.pressHome();
+    }
+
+    @Test
+    public void testTapjacking() throws InterruptedException {
+        Log.d(LOG_TAG, "Starting tap-jacking test");
+
+        launchTestApp();
+
+        launchTapjackedActivity();
+
+        mContext.sendBroadcast(new Intent(Constants.ACTION_START_TAPJACKING));
+        Log.d(LOG_TAG, "Sent intent to start tap-jacking!");
+
+        UiObject2 overlay = waitForView(By.text(mContext.getString(R.string.tapjacking_text)));
+        assertNull("Tap-jacking successful. Overlay was displayed.!", overlay);
+    }
+
+    @After
+    public void tearDown() {
+        mDevice.pressHome();
+    }
+
+    private void launchTestApp() {
+        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(
+                Constants.TEST_APP_PACKAGE);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mContext.startActivity(intent);
+
+        // Wait for the app to appear
+        UiObject2 view = waitForView(By.pkg(Constants.TEST_APP_PACKAGE).depth(0));
+        assertNotNull("test-app did not appear!", view);
+        Log.d(LOG_TAG, "test-app appeared");
+    }
+
+    private void launchTapjackedActivity() {
+        Intent intent = new Intent();
+        intent.setAction("android.settings.action.MANAGE_WRITE_SETTINGS");
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+
+        UiObject2 activityInstance = waitForView(By.pkg("com.android.car.settings").depth(0));
+        assertNotNull("Activity under-test was not launched or found!", activityInstance);
+        Log.d(LOG_TAG, "Started Activity under-test.");
+    }
+
+    private UiObject2 waitForView(BySelector selector) {
+        return mDevice.wait(Until.findObject(selector), WAIT_FOR_UI_TIMEOUT);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/MainActivity.java b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/MainActivity.java
new file mode 100644
index 0000000..7833d26
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/MainActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts.BUG_183411210;
+
+import static android.security.cts.BUG_183411210.Constants.LOG_TAG;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+/** Main activity for the test-app. */
+public final class MainActivity extends AppCompatActivity {
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            startTapjacking();
+        }
+    };
+
+    private Button btnStart;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        registerReceiver(mReceiver, new IntentFilter(Constants.ACTION_START_TAPJACKING));
+
+        btnStart = (Button) findViewById(R.id.btnStart);
+        btnStart.setOnClickListener(v -> startTapjacking());
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+        stopOverlayService();
+    }
+
+    public void startTapjacking() {
+        Log.d(LOG_TAG, "Starting tap-jacking flow.");
+        stopOverlayService();
+
+        startOverlayService();
+        Log.d(LOG_TAG, "Started overlay-service.");
+    }
+
+    private void startOverlayService() {
+        startService(new Intent(getApplicationContext(), OverlayService.class));
+    }
+
+    private void stopOverlayService() {
+        stopService(new Intent(getApplicationContext(), OverlayService.class));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/OverlayService.java b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/OverlayService.java
new file mode 100644
index 0000000..8d27aa8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183411210/src/android/security/cts/BUG_183411210/OverlayService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_183411210;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+/** Service that starts the overlay for the test. */
+public final class OverlayService extends Service {
+    public Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    @Override
+    public void onCreate() {
+        Log.d(Constants.LOG_TAG, "onCreate() called");
+        super.onCreate();
+
+        DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+        int scaledWidth = (int) (displayMetrics.widthPixels * 0.9);
+        int scaledHeight = (int) (displayMetrics.heightPixels * 0.9);
+
+        mWindowManager = getSystemService(WindowManager.class);
+        mLayoutParams = new WindowManager.LayoutParams();
+        mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mLayoutParams.format = PixelFormat.OPAQUE;
+        mLayoutParams.gravity = Gravity.CENTER;
+        mLayoutParams.width = scaledWidth;
+        mLayoutParams.height = scaledHeight;
+        mLayoutParams.x = scaledWidth / 2;
+        mLayoutParams.y = scaledHeight / 2;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.d(Constants.LOG_TAG, "onStartCommand() called");
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(Constants.LOG_TAG, "onDestroy() called");
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        if (!Settings.canDrawOverlays(this)) {
+            Log.w(Constants.LOG_TAG, "Cannot show overlay window. Permission denied");
+        }
+
+        mButton = new Button(getApplicationContext());
+        mButton.setText(getResources().getString(R.string.tapjacking_text));
+        mButton.setTag(mButton.getVisibility());
+        mWindowManager.addView(mButton, mLayoutParams);
+
+        new Handler(Looper.myLooper()).postDelayed(this::stopSelf, 60_000);
+        Log.d(Constants.LOG_TAG, "Floating window created");
+    }
+}
diff --git a/hostsidetests/shortcuts/hostside/AndroidTest.xml b/hostsidetests/shortcuts/hostside/AndroidTest.xml
index 36a0876..bfc33f7 100644
--- a/hostsidetests/shortcuts/hostside/AndroidTest.xml
+++ b/hostsidetests/shortcuts/hostside/AndroidTest.xml
@@ -21,6 +21,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
     <target_preparer class="android.cts.backup.BackupPreparer">
         <option name="enable-backup-if-needed" value="true" />
         <option name="select-local-transport" value="true" />
diff --git a/hostsidetests/silentupdate/Android.bp b/hostsidetests/silentupdate/Android.bp
index c562c6a..641d60b 100644
--- a/hostsidetests/silentupdate/Android.bp
+++ b/hostsidetests/silentupdate/Android.bp
@@ -30,7 +30,9 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    per_testcase_directory: true,
     data: [
+        ":CtsSilentUpdateTestCases",
         ":SilentInstallCurrent",
         ":SilentInstallR",
         ":SilentInstallQ",
diff --git a/hostsidetests/statsdatom/AndroidTest.xml b/hostsidetests/statsdatom/AndroidTest.xml
index e353d1a..fce91f0 100644
--- a/hostsidetests/statsdatom/AndroidTest.xml
+++ b/hostsidetests/statsdatom/AndroidTest.xml
@@ -20,6 +20,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsStatsdAtomHostTestCases.jar" />
     </test>
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
index 6547abf..c7feda6 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
@@ -43,6 +43,7 @@
 
     private static final int APP_OP_RECORD_AUDIO = 27;
     private static final int APP_OP_RECORD_AUDIO_HOTWORD = 102;
+    private static final int APP_OP_ACCESS_RESTRICTED_SETTINGS = 119;
 
     private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
     private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
@@ -102,6 +103,10 @@
         ArrayList<Integer> expectedOps = new ArrayList<>();
         Set<Integer> transformedOps = new HashSet<>(mTransformedFromOp.values());
         for (int i = 0; i < NUM_APP_OPS; i++) {
+            // Ignore access restricted setting as it cannot be read by normal app.
+            if (i == APP_OP_ACCESS_RESTRICTED_SETTINGS) {
+                continue;
+            }
             if (!transformedOps.contains(i)) {
                 expectedOps.add(i);
             }
diff --git a/hostsidetests/systemui/Android.bp b/hostsidetests/systemui/Android.bp
index a5918f4..2c28027 100644
--- a/hostsidetests/systemui/Android.bp
+++ b/hostsidetests/systemui/Android.bp
@@ -37,4 +37,8 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsSystemUiDeviceApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/telephony/Android.bp b/hostsidetests/telephony/Android.bp
index b3d0084..f1bd4a8 100644
--- a/hostsidetests/telephony/Android.bp
+++ b/hostsidetests/telephony/Android.bp
@@ -31,4 +31,8 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    data: [
+        ":TelephonyDeviceTest",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/telephonyprovider/Android.bp b/hostsidetests/telephonyprovider/Android.bp
index 2fa3b71..406c3d6 100644
--- a/hostsidetests/telephonyprovider/Android.bp
+++ b/hostsidetests/telephonyprovider/Android.bp
@@ -31,4 +31,8 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    data: [
+        ":TelephonyProviderDeviceTest",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/theme/Android.bp b/hostsidetests/theme/Android.bp
index 9d1c692..55fdbd2 100644
--- a/hostsidetests/theme/Android.bp
+++ b/hostsidetests/theme/Android.bp
@@ -39,4 +39,8 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsThemeDeviceApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/usage/Android.bp b/hostsidetests/usage/Android.bp
index 2d5b014..1af75f1 100644
--- a/hostsidetests/usage/Android.bp
+++ b/hostsidetests/usage/Android.bp
@@ -31,4 +31,9 @@
         "general-tests",
         "mts",
     ],
+    data: [
+        ":CtsAppUsageTestApp",
+        ":CtsAppUsageTestAppToo",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/webkit/Android.bp b/hostsidetests/webkit/Android.bp
index c76c2d1..734b1b8 100644
--- a/hostsidetests/webkit/Android.bp
+++ b/hostsidetests/webkit/Android.bp
@@ -30,4 +30,8 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsWebViewStartupApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/wifibroadcasts/Android.bp b/hostsidetests/wifibroadcasts/Android.bp
index 30160619..ea1f50d 100644
--- a/hostsidetests/wifibroadcasts/Android.bp
+++ b/hostsidetests/wifibroadcasts/Android.bp
@@ -30,4 +30,8 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    data: [
+        ":CtsWifiBroadcastsDeviceApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/libs/deviceutillegacy/src/android/webkit/cts/WebViewSyncLoader.java b/libs/deviceutillegacy/src/android/webkit/cts/WebViewSyncLoader.java
index 7976f1f..362267c 100644
--- a/libs/deviceutillegacy/src/android/webkit/cts/WebViewSyncLoader.java
+++ b/libs/deviceutillegacy/src/android/webkit/cts/WebViewSyncLoader.java
@@ -32,7 +32,6 @@
 import junit.framework.Assert;
 
 import java.util.Map;
-import java.util.concurrent.Callable;
 
 /**
  * Utility class to simplify tests that need to load data into a WebView and wait for completion
@@ -236,22 +235,12 @@
      * similar functions.
      */
     public void waitForLoadCompletion() {
-        waitForCriteria(WebkitUtils.TEST_TIMEOUT_MS,
-                new Callable<Boolean>() {
-                    @Override
-                    public Boolean call() {
-                        return isLoaded();
-                    }
-                });
-        clearLoad();
-    }
-
-    private void waitForCriteria(long timeout, Callable<Boolean> doneCriteria) {
         if (isUiThread()) {
-            waitOnUiThread(timeout, doneCriteria);
+            waitForLoadCompletionOnUiThread(WebkitUtils.TEST_TIMEOUT_MS);
         } else {
-            waitOnTestThread(timeout, doneCriteria);
+            waitForLoadCompletionOnTestThread(WebkitUtils.TEST_TIMEOUT_MS);
         }
+        clearLoad();
     }
 
     /**
@@ -262,6 +251,14 @@
     }
 
     /**
+     * @return A summary of the current loading status for error reporting.
+     */
+    private synchronized String getLoadStatus() {
+        return "Current load status: mLoaded=" + mLoaded + ", mNewPicture="
+                + mNewPicture + ", mProgress=" + mProgress;
+    }
+
+    /**
      * Makes a WebView call, waits for completion and then resets the
      * load state in preparation for the next load call.
      *
@@ -295,17 +292,17 @@
 
     /**
      * Uses a polling mechanism, while pumping messages to check when the
-     * criteria is met.
+     * load is done.
      */
-    private void waitOnUiThread(long timeout, final Callable<Boolean> doneCriteria) {
+    private void waitForLoadCompletionOnUiThread(long timeout) {
         new PollingCheck(timeout) {
             @Override
             protected boolean check() {
                 pumpMessages();
                 try {
-                    return doneCriteria.call();
+                    return isLoaded();
                 } catch (Exception e) {
-                    Assert.fail("Unexpected error while checking the criteria: "
+                    Assert.fail("Unexpected error while checking load completion: "
                             + e.getMessage());
                     return true;
                 }
@@ -314,21 +311,23 @@
     }
 
     /**
-     * Uses a wait/notify to check when the criteria is met.
+     * Uses a wait/notify to check when the load is done.
      */
-    private synchronized void waitOnTestThread(long timeout, Callable<Boolean> doneCriteria) {
+    private synchronized void waitForLoadCompletionOnTestThread(long timeout) {
         try {
             long waitEnd = SystemClock.uptimeMillis() + timeout;
             long timeRemaining = timeout;
-            while (!doneCriteria.call() && timeRemaining > 0) {
+            while (!isLoaded() && timeRemaining > 0) {
                 this.wait(timeRemaining);
                 timeRemaining = waitEnd - SystemClock.uptimeMillis();
             }
-            Assert.assertTrue("Action failed to complete before timeout", doneCriteria.call());
+            if (!isLoaded()) {
+                Assert.fail("Action failed to complete before timeout: " + getLoadStatus());
+            }
         } catch (InterruptedException e) {
             // We'll just drop out of the loop and fail
         } catch (Exception e) {
-            Assert.fail("Unexpected error while checking the criteria: "
+            Assert.fail("Unexpected error while checking load completion: "
                     + e.getMessage());
         }
     }
diff --git a/tests/BlobStore/Android.bp b/tests/BlobStore/Android.bp
index 7fcb613..e1173d4 100644
--- a/tests/BlobStore/Android.bp
+++ b/tests/BlobStore/Android.bp
@@ -36,7 +36,13 @@
         "cts",
         "general-tests",
     ],
-    sdk_version: "test_current"
+    sdk_version: "test_current",
+    data: [
+        ":CtsBlobStoreTestHelper",
+        ":CtsBlobStoreTestHelperDiffSig",
+        ":CtsBlobStoreTestHelperDiffSig2",
+    ],
+    per_testcase_directory: true,
 }
 
 android_test_helper_app {
diff --git a/tests/JobScheduler/Android.bp b/tests/JobScheduler/Android.bp
index c4f8018..ec39138 100644
--- a/tests/JobScheduler/Android.bp
+++ b/tests/JobScheduler/Android.bp
@@ -38,4 +38,8 @@
     ],
     // sdk_version: "current",
     platform_apis: true,
+    data: [
+        ":CtsJobTestApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobInfoTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobInfoTest.java
index 2c54508..3f4a767 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobInfoTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobInfoTest.java
@@ -22,6 +22,7 @@
 import android.app.job.JobInfo;
 import android.content.ClipData;
 import android.content.Intent;
+import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.Uri;
 import android.os.Bundle;
@@ -495,6 +496,7 @@
         JobInfo ji = new JobInfo.Builder(JOB_ID, kJobServiceComponent)
                 .build();
         assertEquals(JobInfo.NETWORK_TYPE_NONE, ji.getNetworkType());
+        assertNull(ji.getRequiredNetwork());
         // Confirm JobScheduler accepts the JobInfo object.
         mJobScheduler.schedule(ji);
 
@@ -502,6 +504,14 @@
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                 .build();
         assertEquals(JobInfo.NETWORK_TYPE_ANY, ji.getNetworkType());
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN));
         // Confirm JobScheduler accepts the JobInfo object.
         mJobScheduler.schedule(ji);
 
@@ -509,6 +519,14 @@
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
                 .build();
         assertEquals(JobInfo.NETWORK_TYPE_UNMETERED, ji.getNetworkType());
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN));
         // Confirm JobScheduler accepts the JobInfo object.
         mJobScheduler.schedule(ji);
 
@@ -516,6 +534,14 @@
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING)
                 .build();
         assertEquals(JobInfo.NETWORK_TYPE_NOT_ROAMING, ji.getNetworkType());
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN));
         // Confirm JobScheduler accepts the JobInfo object.
         mJobScheduler.schedule(ji);
 
@@ -523,6 +549,14 @@
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR)
                 .build();
         assertEquals(JobInfo.NETWORK_TYPE_CELLULAR, ji.getNetworkType());
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        assertTrue(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+        assertFalse(ji.getRequiredNetwork()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN));
         // Confirm JobScheduler accepts the JobInfo object.
         mJobScheduler.schedule(ji);
 
@@ -530,6 +564,7 @@
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
                 .build();
         assertEquals(JobInfo.NETWORK_TYPE_NONE, ji.getNetworkType());
+        assertNull(ji.getRequiredNetwork());
         // Confirm JobScheduler accepts the JobInfo object.
         mJobScheduler.schedule(ji);
     }
diff --git a/tests/JobSchedulerSharedUid/Android.bp b/tests/JobSchedulerSharedUid/Android.bp
index ee30d75..05fc1f3 100644
--- a/tests/JobSchedulerSharedUid/Android.bp
+++ b/tests/JobSchedulerSharedUid/Android.bp
@@ -39,4 +39,10 @@
     //sdk_version: "current"
     platform_apis: true,
 
+    data: [
+        ":CtsJobSchedulerJobPerm",
+        ":CtsJobSchedulerSharedUid",
+        ":CtsJobSharedUidTestApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index bbce105..9ac38e9 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -24,6 +24,11 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <!--  Some tests use sticky broadcasts to ensure that inline suggestion extras
+    are delivered to the IME even when its process is not running persistently.
+    This can happen when the IME is unbound as a result of enabling
+    the config_preventImeStartupUnlessTextEditor option. -->
+    <uses-permission android:name="android.permission.BROADCAST_STICKY"/>
 
     <application>
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/activities/AuthenticationActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/AuthenticationActivity.java
index 0a32981..d507dd7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/activities/AuthenticationActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/AuthenticationActivity.java
@@ -68,6 +68,12 @@
      */
     private static final String EXTRA_OUTPUT_IS_EPHEMERAL_DATASET = "output_is_ephemeral_dataset";
 
+    /**
+     * When launched with a non-null intent associated with this extra, the intent will be returned
+     * as the response.
+     */
+    private static final String EXTRA_RESPONSE_INTENT = "response_intent";
+
 
     private static final int MSG_WAIT_FOR_LATCH = 1;
     private static final int MSG_REQUEST_AUTOFILL = 2;
@@ -117,6 +123,10 @@
         return createSender(context, id, dataset, null);
     }
 
+    public static IntentSender createSender(Context context, Intent responseIntent) {
+        return createSender(context, null, 1, null, null, responseIntent);
+    }
+
     public static IntentSender createSender(Context context, int id,
             CannedDataset dataset, Bundle outClientState) {
         return createSender(context, id, dataset, outClientState, null);
@@ -127,14 +137,14 @@
         Preconditions.checkArgument(id > 0, "id must be positive");
         Preconditions.checkState(sDatasets.get(id) == null, "already have id");
         sDatasets.put(id, dataset);
-        return createSender(context, EXTRA_DATASET_ID, id, outClientState, isEphemeralDataset);
+        return createSender(context, EXTRA_DATASET_ID, id, outClientState, isEphemeralDataset,
+                null);
     }
 
     /**
      * Creates an {@link IntentSender} with the given unique id for the given fill response.
      */
-    public static IntentSender createSender(Context context, int id,
-            CannedFillResponse response) {
+    public static IntentSender createSender(Context context, int id, CannedFillResponse response) {
         return createSender(context, id, response, null);
     }
 
@@ -143,12 +153,12 @@
         Preconditions.checkArgument(id > 0, "id must be positive");
         Preconditions.checkState(sResponses.get(id) == null, "already have id");
         sResponses.put(id, response);
-        return createSender(context, EXTRA_RESPONSE_ID, id, outData, null);
+        return createSender(context, EXTRA_RESPONSE_ID, id, outData, null, null);
     }
 
     private static IntentSender createSender(Context context, String extraName, int id,
-            Bundle outClientState, Boolean isEphemeralDataset) {
-        final Intent intent = new Intent(context, AuthenticationActivity.class);
+            Bundle outClientState, Boolean isEphemeralDataset, Intent responseIntent) {
+        Intent intent = new Intent(context, AuthenticationActivity.class);
         intent.putExtra(extraName, id);
         if (outClientState != null) {
             Log.d(TAG, "Create with " + outClientState + " as " + EXTRA_OUTPUT_CLIENT_STATE);
@@ -159,6 +169,7 @@
                     + EXTRA_OUTPUT_IS_EPHEMERAL_DATASET);
             intent.putExtra(EXTRA_OUTPUT_IS_EPHEMERAL_DATASET, isEphemeralDataset);
         }
+        intent.putExtra(EXTRA_RESPONSE_INTENT, responseIntent);
         final PendingIntent pendingIntent =
                 PendingIntent.getActivity(context, id, intent, PendingIntent.FLAG_MUTABLE);
         sPendingIntents.add(pendingIntent);
@@ -267,6 +278,20 @@
     }
 
     private void doIt() {
+        final int resultCode;
+        synchronized (sLock) {
+            resultCode = sResultCode;
+        }
+
+        // If responseIntent is provided, use that to return, otherwise contstruct the response.
+        Intent responseIntent = getIntent().getParcelableExtra(EXTRA_RESPONSE_INTENT, Intent.class);
+        if (responseIntent != null) {
+            Log.d(TAG, "Returning code " + resultCode);
+            setResult(resultCode, responseIntent);
+            finish();
+            return;
+        }
+
         // We should get the assist structure...
         final AssistStructure structure = getIntent().getParcelableExtra(
                 AutofillManager.EXTRA_ASSIST_STRUCTURE);
@@ -313,11 +338,6 @@
             intent.putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET,
                     isEphemeralDataset);
         }
-
-        final int resultCode;
-        synchronized (sLock) {
-            resultCode = sResultCode;
-        }
         Log.d(TAG, "Returning code " + resultCode);
         setResult(resultCode, intent);
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dropdown/AuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/dropdown/AuthenticationTest.java
index d8c10dd..d9a84fd 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dropdown/AuthenticationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dropdown/AuthenticationTest.java
@@ -38,6 +38,7 @@
 import android.autofillservice.cts.testcore.Helper;
 import android.autofillservice.cts.testcore.InstrumentedAutoFillService.SaveRequest;
 import android.autofillservice.cts.testcore.MyAutofillCallback;
+import android.content.Intent;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
@@ -977,7 +978,20 @@
         fillResponseAuthServiceHasNoDataTest(false);
     }
 
+    // Tests fix for bug in Android 11 where app crashes when autofill provider return empty Intent
+    // with success from authentication activity.
+    @Test
+    @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
+    public void testFillResponseAuthServiceReturnsEmptyIntent() throws Exception {
+        fillResponseAuthServiceHasNoDataTest(false, new Intent());
+    }
+
     private void fillResponseAuthServiceHasNoDataTest(boolean canSave) throws Exception {
+        fillResponseAuthServiceHasNoDataTest(canSave, null);
+    }
+
+    private void fillResponseAuthServiceHasNoDataTest(boolean canSave, Intent responseIntent)
+            throws Exception {
         // Set service.
         enableService();
         final MyAutofillCallback callback = mActivity.registerCallback();
@@ -989,8 +1003,12 @@
                         .build()
                 : CannedFillResponse.NO_RESPONSE;
 
-        final IntentSender authentication =
-                AuthenticationActivity.createSender(mContext, 1, response);
+        final IntentSender authentication;
+        if (responseIntent != null) {
+            authentication = AuthenticationActivity.createSender(mContext, responseIntent);
+        } else {
+            authentication = AuthenticationActivity.createSender(mContext, 1, response);
+        }
 
         // Configure the service behavior
         sReplier.addResponse(new CannedFillResponse.Builder()
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
index 123e133..230b75a 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
@@ -25,16 +25,20 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
+import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.DeviceStateRequest;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.PollingCheck;
 
@@ -42,6 +46,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /** CTS tests for {@link DeviceStateManager} API(s). */
@@ -50,6 +56,8 @@
 
     public static final int TIMEOUT = 2000;
 
+    private static final int INVALID_DEVICE_STATE = -1;
+
     /**
      * Tests that {@link DeviceStateManager#getSupportedStates()} returns at least one state and
      * that none of the returned states are in the range
@@ -119,20 +127,27 @@
 
     /**
      * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor,
-     * DeviceStateRequest.Callback)} is successful and results in a registered callback being
-     * triggered with a value equal to the requested state.
+     * DeviceStateRequest.Callback)} is not successful and results in a failure to change the
+     * state of the device due to the state requested not being available for apps to request.
      */
     @Test
-    public void testRequestStateSucceedsAsTopApp() throws IllegalArgumentException {
+    public void testRequestStateFailsAsTopApp_ifStateNotDefinedAsAvailableForAppsToRequest()
+            throws IllegalArgumentException {
         final DeviceStateManager manager = getDeviceStateManager();
         final int[] supportedStates = manager.getSupportedStates();
         // We want to verify that the app can change device state
         // So we only attempt if there are more than 1 possible state.
         assumeTrue(supportedStates.length > 1);
+        Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(), supportedStates);
+        // checks that not every state is available for an app to request
+        assumeTrue(statesAvailableToRequest.size() < supportedStates.length);
+
+        Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates);
 
         final StateTrackingCallback callback = new StateTrackingCallback();
         manager.registerCallback(Runnable::run, callback);
-        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState != -1);
+        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState != INVALID_DEVICE_STATE);
         final TestActivitySession<DeviceStateTestActivity> activitySession =
                 createManagedTestActivitySession();
 
@@ -143,13 +158,65 @@
 
         DeviceStateTestActivity activity = activitySession.getActivity();
 
-        int newState = determineNewState(callback.mCurrentState, supportedStates);
-        activity.requestDeviceStateChange(newState);
+        Set<Integer> possibleStates = possibleStates(false /* shouldSucceed */,
+                availableDeviceStates,
+                statesAvailableToRequest);
+        int nextState = calculateDifferentState(callback.mCurrentState, possibleStates);
+        // checks that we were able to find a valid state to request.
+        assumeTrue(nextState != INVALID_DEVICE_STATE);
 
-        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == newState);
+        activity.requestDeviceStateChange(nextState);
 
-        assertEquals(newState, callback.mCurrentState);
+        assertTrue(activity.requestStateFailed);
+    }
+
+    /**
+     * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor,
+     * DeviceStateRequest.Callback)} is successful and results in a registered callback being
+     * triggered with a value equal to the requested state.
+     */
+    @Test
+    public void testRequestStateSucceedsAsTopApp_ifStateDefinedAsAvailableForAppsToRequest() {
+        final DeviceStateManager manager = getDeviceStateManager();
+        final int[] supportedStates = manager.getSupportedStates();
+
+        // We want to verify that the app can change device state
+        // So we only attempt if there are more than 1 possible state.
+        assumeTrue(supportedStates.length > 1);
+        Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(), supportedStates);
+        assumeTrue(statesAvailableToRequest.size() > 0);
+
+        Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates);
+
+        final StateTrackingCallback callback = new StateTrackingCallback();
+        manager.registerCallback(Runnable::run, callback);
+        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState != INVALID_DEVICE_STATE);
+        final TestActivitySession<DeviceStateTestActivity> activitySession =
+                createManagedTestActivitySession();
+
+        activitySession.launchTestActivityOnDisplaySync(
+                DeviceStateTestActivity.class,
+                DEFAULT_DISPLAY
+        );
+
+        DeviceStateTestActivity activity = activitySession.getActivity();
+
+        Set<Integer> possibleStates = possibleStates(true /* shouldSucceed */,
+                availableDeviceStates,
+                statesAvailableToRequest);
+        int nextState = calculateDifferentState(callback.mCurrentState, possibleStates);
+        // checks that we were able to find a valid state to request.
+        assumeTrue(nextState != INVALID_DEVICE_STATE);
+
+        activity.requestDeviceStateChange(nextState);
+
+        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == nextState);
+
+        assertEquals(nextState, callback.mCurrentState);
         assertFalse(activity.requestStateFailed);
+
+        manager.cancelStateRequest(); // reset device state after successful request
     }
 
     /**
@@ -163,10 +230,15 @@
         // We want to verify that the app can change device state
         // So we only attempt if there are more than 1 possible state.
         assumeTrue(supportedStates.length > 1);
+        Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(), supportedStates);
+        assumeTrue(statesAvailableToRequest.size() > 0);
+
+        Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates);
 
         final StateTrackingCallback callback = new StateTrackingCallback();
         manager.registerCallback(Runnable::run, callback);
-        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState != -1);
+        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState != INVALID_DEVICE_STATE);
 
         final TestActivitySession<DeviceStateTestActivity> activitySession =
                 createManagedTestActivitySession();
@@ -180,8 +252,14 @@
 
         launchHomeActivity(); // places our test activity in the background
 
-        int requestedState = determineNewState(callback.mCurrentState, supportedStates);
-        activity.requestDeviceStateChange(requestedState);
+        Set<Integer> possibleStates = possibleStates(true /* shouldSucceed */,
+                availableDeviceStates,
+                statesAvailableToRequest);
+        int nextState = calculateDifferentState(callback.mCurrentState, possibleStates);
+        // checks that we were able to find a valid state to request.
+        assumeTrue(nextState != INVALID_DEVICE_STATE);
+
+        activity.requestDeviceStateChange(nextState);
 
         assertTrue(activity.requestStateFailed);
     }
@@ -197,10 +275,15 @@
         // We want to verify that the app can change device state
         // So we only attempt if there are more than 1 possible state.
         assumeTrue(supportedStates.length > 1);
+        Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(), supportedStates);
+        assumeFalse(statesAvailableToRequest.isEmpty());
+
+        Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates);
 
         final StateTrackingCallback callback = new StateTrackingCallback();
         manager.registerCallback(Runnable::run, callback);
-        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState != -1);
+        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState != INVALID_DEVICE_STATE);
         final TestActivitySession<DeviceStateTestActivity> activitySession =
                 createManagedTestActivitySession();
 
@@ -212,12 +295,19 @@
         DeviceStateTestActivity activity = activitySession.getActivity();
 
         int originalState = callback.mCurrentState;
-        int newState = determineNewState(callback.mCurrentState, supportedStates);
-        activity.requestDeviceStateChange(newState);
 
-        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == newState);
+        Set<Integer> possibleStates = possibleStates(true /* shouldSucceed */,
+                availableDeviceStates,
+                statesAvailableToRequest);
+        int nextState = calculateDifferentState(callback.mCurrentState, possibleStates);
+        // checks that we were able to find a valid state to request.
+        assumeTrue(nextState != INVALID_DEVICE_STATE);
 
-        assertEquals(newState, callback.mCurrentState);
+        activity.requestDeviceStateChange(nextState);
+
+        PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == nextState);
+
+        assertEquals(nextState, callback.mCurrentState);
         assertFalse(activity.requestStateFailed);
 
         activity.finish();
@@ -230,7 +320,7 @@
         );
         // verify that the overridden state is still active after finishing
         // and launching the second activity.
-        assertEquals(newState, callback.mCurrentState);
+        assertEquals(nextState, callback.mCurrentState);
 
         activity = secondActivitySession.getActivity();
         activity.cancelOverriddenState();
@@ -240,18 +330,113 @@
         assertEquals(originalState, callback.mCurrentState);
     }
 
-    // determine what state we should request that isn't the current state
-    // throws an IllegalArgumentException if there is no unique states available
-    // in the list of supported states
-    private static int determineNewState(int currentState, int[] states)
-            throws IllegalArgumentException {
-        for (int state : states) {
+
+    /**
+     * Reads in the states that are available to be requested by apps from the configuration file
+     * and returns a set of all valid states that are read in.
+     *
+     * @param context The context used to get the configuration values from {@link Resources}
+     * @param supportedStates The device states that are supported on that device.
+     * @return {@link Set} of valid device states that are read in.
+     */
+    private static Set<Integer> getAvailableStatesToRequest(Context context,
+            int[] supportedStates) {
+        Set<Integer> availableStatesToRequest = new HashSet<>();
+        String[] availableStateIdentifiers = context.getResources().getStringArray(
+                Resources.getSystem().getIdentifier("config_deviceStatesAvailableForAppRequests",
+                        "array",
+                        "android"));
+        for (String identifier : availableStateIdentifiers) {
+            int stateIdentifier = context.getResources()
+                    .getIdentifier(identifier, "integer", "android");
+            int state = context.getResources().getInteger(stateIdentifier);
+            if (isValidState(state, supportedStates)) {
+                availableStatesToRequest.add(context.getResources().getInteger(stateIdentifier));
+            }
+        }
+        return availableStatesToRequest;
+    }
+
+    private static boolean isValidState(int state, int[] supportedStates) {
+        for (int i = 0; i < supportedStates.length; i++) {
+            if (state == supportedStates[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Generates a set of possible device states based on a {@link Set} of valid device states,
+     * {@code supportedDeviceStates}, and the set of device states available to be requested
+     * {@code availableStatesToRequest}, as well as if the request should succeed or not, given by
+     * {@code shouldSucceed}.
+     *
+     * If {@code shouldSucceed} is {@code true}, we only return device states that are available,
+     * and if it is {@code false}, we only return non available device states.
+     *
+     * @param availableStatesToRequest The states that are available to be requested from an app
+     * @param shouldSucceed Should the request succeed or not, to determine what states we return
+     * @param supportedDeviceStates All states supported on the device.
+     * {@throws} an {@link IllegalArgumentException} if {@code availableStatesToRequest} includes
+     * non-valid device states.
+     */
+    private static Set<Integer> possibleStates(boolean shouldSucceed,
+            Set<Integer> supportedDeviceStates,
+            Set<Integer> availableStatesToRequest) {
+
+        if (!supportedDeviceStates.containsAll(availableStatesToRequest)) {
+            throw new IllegalArgumentException("Available states include invalid device states");
+        }
+
+        Set<Integer> availableStates = new HashSet<>(supportedDeviceStates);
+
+        if (shouldSucceed) {
+            availableStates.retainAll(availableStatesToRequest);
+        } else {
+            availableStates.removeAll(availableStatesToRequest);
+        }
+
+        return availableStates;
+    }
+
+    /**
+     * Determines what state we should request that isn't the current state, and is included
+     * in {@code possibleStates}. If there is no state that fits these requirements, we return
+     * {@link INVALID_DEVICE_STATE}.
+     *
+     * @param currentState The current state of the device
+     * @param possibleStates States that we can request
+     */
+    private static int calculateDifferentState(int currentState, Set<Integer> possibleStates) {
+        if (possibleStates.isEmpty()) {
+            return INVALID_DEVICE_STATE;
+        }
+        if (possibleStates.size() == 1 && possibleStates.contains(currentState)) {
+            return INVALID_DEVICE_STATE;
+        }
+        for (int state: possibleStates) {
             if (state != currentState) {
                 return state;
             }
         }
-        throw new IllegalArgumentException(
-                "No unique supported states besides our current state were found");
+        return INVALID_DEVICE_STATE;
+    }
+
+    /**
+     * Creates a {@link Set} of values that are in the {@code states} array.
+     *
+     * Used to create a {@link Set} from the available device states that {@link DeviceStateManager}
+     * returns as an array.
+     *
+     * @param states Device states that are supported on the device
+     */
+    private static Set<Integer> generateDeviceStateSet(int[] states) {
+        Set<Integer> supportedStates = new HashSet<>();
+        for (int i = 0; i < states.length; i++) {
+            supportedStates.add(states[i]);
+        }
+        return supportedStates;
     }
 
     /**
diff --git a/tests/framework/base/biometrics/Android.bp b/tests/framework/base/biometrics/Android.bp
index 66c8134..1ec7d5b 100644
--- a/tests/framework/base/biometrics/Android.bp
+++ b/tests/framework/base/biometrics/Android.bp
@@ -22,6 +22,7 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
+        "sts",
         "vts10",
         "general-tests",
     ],
@@ -45,6 +46,7 @@
     srcs: ["src/**/*.java"],
     data: [
         ":CtsBiometricServiceTestApp",
+        ":CtsBiometricServiceUtilTestApp",
         ":CtsFingerprintServiceTestApp",
     ],
     sdk_version: "test_current",
diff --git a/tests/framework/base/biometrics/AndroidTest.xml b/tests/framework/base/biometrics/AndroidTest.xml
index 1e7854c..0c020d8 100644
--- a/tests/framework/base/biometrics/AndroidTest.xml
+++ b/tests/framework/base/biometrics/AndroidTest.xml
@@ -24,6 +24,7 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsBiometricsTestCases.apk" />
         <option name="test-file-name" value="CtsBiometricServiceTestApp.apk" />
+        <option name="test-file-name" value="CtsBiometricServiceUtilTestApp.apk" />
         <option name="test-file-name" value="CtsFingerprintServiceTestApp.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/framework/base/biometrics/OWNERS b/tests/framework/base/biometrics/OWNERS
index 14fbfd7..95749d0 100644
--- a/tests/framework/base/biometrics/OWNERS
+++ b/tests/framework/base/biometrics/OWNERS
@@ -5,4 +5,3 @@
 jaggies@google.com
 jbolinger@google.com
 joshmccloskey@google.com
-kchyn@google.com
diff --git a/tests/framework/base/biometrics/apps/biometrics/OWNERS b/tests/framework/base/biometrics/apps/biometrics/OWNERS
index 15711bb..95749d0 100644
--- a/tests/framework/base/biometrics/apps/biometrics/OWNERS
+++ b/tests/framework/base/biometrics/apps/biometrics/OWNERS
@@ -1,2 +1,7 @@
 # Bug component: 879035
-kchyn@google.com
\ No newline at end of file
+
+graciecheng@google.com
+ilyamaty@google.com
+jaggies@google.com
+jbolinger@google.com
+joshmccloskey@google.com
diff --git a/tests/framework/base/biometrics/apps/fingerprint/Android.bp b/tests/framework/base/biometrics/apps/fingerprint/Android.bp
index 295404e..ef7ceb4a 100644
--- a/tests/framework/base/biometrics/apps/fingerprint/Android.bp
+++ b/tests/framework/base/biometrics/apps/fingerprint/Android.bp
@@ -34,6 +34,7 @@
 
     test_suites: [
         "cts",
+        "sts",
         "vts10",
         "general-tests",
     ],
diff --git a/tests/framework/base/biometrics/apps/fingerprint/OWNERS b/tests/framework/base/biometrics/apps/fingerprint/OWNERS
index 15711bb..95749d0 100644
--- a/tests/framework/base/biometrics/apps/fingerprint/OWNERS
+++ b/tests/framework/base/biometrics/apps/fingerprint/OWNERS
@@ -1,2 +1,7 @@
 # Bug component: 879035
-kchyn@google.com
\ No newline at end of file
+
+graciecheng@google.com
+ilyamaty@google.com
+jaggies@google.com
+jbolinger@google.com
+joshmccloskey@google.com
diff --git a/tests/framework/base/biometrics/apps/fingerprint/src/android/server/biometrics/fingerprint/AuthOnCreateActivity.java b/tests/framework/base/biometrics/apps/fingerprint/src/android/server/biometrics/fingerprint/AuthOnCreateActivity.java
index 85a9230..c870e6b 100644
--- a/tests/framework/base/biometrics/apps/fingerprint/src/android/server/biometrics/fingerprint/AuthOnCreateActivity.java
+++ b/tests/framework/base/biometrics/apps/fingerprint/src/android/server/biometrics/fingerprint/AuthOnCreateActivity.java
@@ -28,7 +28,6 @@
  */
 @SuppressWarnings("deprecation")
 public class AuthOnCreateActivity extends Activity {
-    private static final String TAG = "AuthOnCreateActivity";
 
     @Override
     protected void onCreate(@Nullable Bundle bundle) {
diff --git a/tests/framework/base/biometrics/apps/util/Android.bp b/tests/framework/base/biometrics/apps/util/Android.bp
new file mode 100644
index 0000000..5fa1367
--- /dev/null
+++ b/tests/framework/base/biometrics/apps/util/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CtsBiometricServiceUtilTestApp",
+    defaults: ["cts_support_defaults"],
+
+    static_libs: [
+        "cts-biometric-util",
+        "cts-wm-app-base",
+    ],
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    sdk_version: "test_current",
+    per_testcase_directory: true,
+
+    test_suites: [
+        "cts",
+        "sts",
+        "vts10",
+        "general-tests",
+    ],
+}
diff --git a/tests/framework/base/biometrics/apps/util/AndroidManifest.xml b/tests/framework/base/biometrics/apps/util/AndroidManifest.xml
new file mode 100644
index 0000000..05d39f2
--- /dev/null
+++ b/tests/framework/base/biometrics/apps/util/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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.server.biometrics.util">
+
+    <uses-permission android:name="android.permission.USE_BIOMETRIC"/>
+
+    <application>
+        <activity
+            android:name="android.server.biometrics.util.EmptyActivity"
+            android:exported="true"/>
+    </application>
+
+</manifest>
diff --git a/tests/framework/base/biometrics/apps/util/OWNERS b/tests/framework/base/biometrics/apps/util/OWNERS
new file mode 100644
index 0000000..95749d0
--- /dev/null
+++ b/tests/framework/base/biometrics/apps/util/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 879035
+
+graciecheng@google.com
+ilyamaty@google.com
+jaggies@google.com
+jbolinger@google.com
+joshmccloskey@google.com
diff --git a/tests/framework/base/biometrics/apps/util/res/layout/empty_activity.xml b/tests/framework/base/biometrics/apps/util/res/layout/empty_activity.xml
new file mode 100644
index 0000000..b7c8acb
--- /dev/null
+++ b/tests/framework/base/biometrics/apps/util/res/layout/empty_activity.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+</LinearLayout>
diff --git a/tests/framework/base/biometrics/apps/util/src/android/server/biometrics/util/EmptyActivity.java b/tests/framework/base/biometrics/apps/util/src/android/server/biometrics/util/EmptyActivity.java
new file mode 100644
index 0000000..b5f3d28
--- /dev/null
+++ b/tests/framework/base/biometrics/apps/util/src/android/server/biometrics/util/EmptyActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.biometrics.util;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/** Blank activity. */
+public class EmptyActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.empty_activity);
+    }
+}
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
index 6fa9022..1bb7eea 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
@@ -72,7 +72,7 @@
 /**
  * Base class containing useful functionality. Actual tests should be done in subclasses.
  */
-abstract class BiometricTestBase extends ActivityManagerTestBase {
+abstract class BiometricTestBase extends ActivityManagerTestBase implements TestSessionList.Idler {
 
     private static final String TAG = "BiometricTestBase";
     private static final String DUMPSYS_BIOMETRIC = Utils.DUMPSYS_BIOMETRIC;
@@ -108,7 +108,8 @@
         super.launchActivity(componentName);
     }
 
-    void waitForIdleSensors() {
+    @Override
+    public void waitForIdleSensors() {
         try {
             Utils.waitForIdleService(this::getSensorStates);
         } catch (Exception e) {
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/TestSessionList.java b/tests/framework/base/biometrics/src/android/server/biometrics/TestSessionList.java
index 7ff7431..fda30f9 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/TestSessionList.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/TestSessionList.java
@@ -33,12 +33,18 @@
  * Prefer to simply use a try block with a single session when possible.
  */
 public class TestSessionList implements AutoCloseable {
-    private final BiometricTestBase mTest;
+    private final Idler mIdler;
     private final List<BiometricTestSession> mSessions = new ArrayList<>();
     private final Map<Integer, BiometricTestSession> mSessionMap = new HashMap<>();
 
-    public TestSessionList(@NonNull BiometricTestBase test) {
-        mTest = test;
+    public interface Idler {
+        /** Wait for all sensor to be idle. */
+        void waitForIdleSensors();
+    }
+
+    /** Create a list with the given idler.  */
+    public TestSessionList(@NonNull Idler idler) {
+        mIdler = idler;
     }
 
     /** Add a session. */
@@ -69,6 +75,6 @@
         for (BiometricTestSession session : mSessions) {
             session.close();
         }
-        mTest.waitForIdleSensors();
+        mIdler.waitForIdleSensors();
     }
 }
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/fingerprint/FingerprintServiceTest.java b/tests/framework/base/biometrics/src/android/server/biometrics/fingerprint/FingerprintServiceTest.java
index a81d5c6..7868109 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/fingerprint/FingerprintServiceTest.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/fingerprint/FingerprintServiceTest.java
@@ -16,12 +16,16 @@
 
 package android.server.biometrics.fingerprint;
 
-import static android.server.biometrics.SensorStates.SensorState;
-import static android.server.biometrics.SensorStates.UserState;
+import static android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_CANCELED;
+import static android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED;
 import static android.server.biometrics.fingerprint.Components.AUTH_ON_CREATE_ACTIVITY;
+import static android.server.biometrics.util.Components.EMPTY_ACTIVITY;
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -33,15 +37,21 @@
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.Bundle;
+import android.platform.test.annotations.AsbSecurityTest;
 import android.platform.test.annotations.Presubmit;
 import android.server.biometrics.BiometricServiceState;
 import android.server.biometrics.SensorStates;
+import android.server.biometrics.TestSessionList;
 import android.server.biometrics.Utils;
 import android.server.wm.ActivityManagerTestBase;
 import android.server.wm.TestJournalProvider.TestJournal;
 import android.server.wm.TestJournalProvider.TestJournalContainer;
 import android.server.wm.UiDeviceUtils;
-import android.server.wm.WindowManagerState;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -54,16 +64,19 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 @SuppressWarnings("deprecation")
 @Presubmit
-public class FingerprintServiceTest extends ActivityManagerTestBase {
+public class FingerprintServiceTest extends ActivityManagerTestBase
+        implements TestSessionList.Idler {
     private static final String TAG = "FingerprintServiceTest";
 
     private static final String DUMPSYS_FINGERPRINT = "dumpsys fingerprint --proto --state";
+    private static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
+    private static final long WAIT_MS = 2000;
+    private static final BySelector SELECTOR_BIOMETRIC_PROMPT =
+            By.res("com.android.systemui", "biometric_scrollview");
 
     private SensorStates getSensorStates() throws Exception {
         final byte[] dump = Utils.executeShellCommand(DUMPSYS_FINGERPRINT);
@@ -71,6 +84,15 @@
         return SensorStates.parseFrom(proto);
     }
 
+    @Override
+    public void waitForIdleSensors() {
+        try {
+            Utils.waitForIdleService(this::getSensorStates);
+        } catch (Exception e) {
+            Log.e(TAG, "Exception when waiting for idle", e);
+        }
+    }
+
     @Nullable
     private static FingerprintCallbackHelper.State getCallbackState(@NonNull TestJournal journal) {
         Utils.waitFor("Waiting for authentication callback",
@@ -94,10 +116,12 @@
     @NonNull private Instrumentation mInstrumentation;
     @Nullable private FingerprintManager mFingerprintManager;
     @NonNull private List<SensorProperties> mSensorProperties;
+    @NonNull private UiDevice mDevice;
 
     @Before
     public void setUp() throws Exception {
         mInstrumentation = getInstrumentation();
+        mDevice = UiDevice.getInstance(mInstrumentation);
         mFingerprintManager = mInstrumentation.getContext()
                 .getSystemService(FingerprintManager.class);
 
@@ -110,35 +134,21 @@
 
         // Tests can be skipped on devices without fingerprint sensors
         assumeTrue(!mSensorProperties.isEmpty());
+
+        // Turn screen on and dismiss keyguard
+        UiDeviceUtils.pressWakeupButton();
+        UiDeviceUtils.pressUnlockButton();
     }
 
     @After
     public void cleanup() throws Exception {
-        if (mFingerprintManager == null || mSensorProperties.isEmpty()) {
-            // The tests were skipped anyway, nothing to clean up. Maybe we can use JUnit test
-            // annotations in the future.
+        if (mFingerprintManager == null) {
             return;
         }
 
-
         mInstrumentation.waitForIdleSync();
         Utils.waitForIdleService(this::getSensorStates);
 
-        final SensorStates sensorStates = getSensorStates();
-        for (Map.Entry<Integer, SensorState> sensorEntry : sensorStates.sensorStates.entrySet()) {
-            for (Map.Entry<Integer, UserState> userEntry
-                    : sensorEntry.getValue().getUserStates().entrySet()) {
-                if (userEntry.getValue().numEnrolled != 0) {
-                    Log.w(TAG, "Cleaning up for sensor: " + sensorEntry.getKey()
-                            + ", user: " + userEntry.getKey());
-                    BiometricTestSession session =
-                            mFingerprintManager.createTestSession(sensorEntry.getKey());
-                    session.cleanupInternalState(userEntry.getKey());
-                    session.close();
-                }
-            }
-        }
-
         mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
     }
 
@@ -174,75 +184,157 @@
     @Test
     public void testAuthenticateFromForegroundActivity() throws Exception {
         assumeTrue(Utils.isFirstApiLevel29orGreater());
-        // Turn screen on and dismiss keyguard
-        UiDeviceUtils.pressWakeupButton();
-        UiDeviceUtils.pressUnlockButton();
 
         // Manually keep track and close the sessions, since we want to enroll all sensors before
         // requesting auth.
-        final List<BiometricTestSession> testSessions = new ArrayList<>();
-
         final int userId = 0;
-        for (SensorProperties prop : mSensorProperties) {
-            BiometricTestSession session =
-                    mFingerprintManager.createTestSession(prop.getSensorId());
-            testSessions.add(session);
+        try (TestSessionList testSessions = createTestSessionsWithEnrollments(userId)) {
+            final TestJournal journal = TestJournalContainer.get(AUTH_ON_CREATE_ACTIVITY);
 
-            session.startEnroll(userId);
+            // Launch test activity
+            launchActivity(AUTH_ON_CREATE_ACTIVITY);
+            mWmState.waitForActivityState(AUTH_ON_CREATE_ACTIVITY, STATE_RESUMED);
             mInstrumentation.waitForIdleSync();
-            Utils.waitForIdleService(this::getSensorStates);
 
-            session.finishEnroll(userId);
+            // At least one sensor should be authenticating
+            assertFalse(getSensorStates().areAllSensorsIdle());
+
+            // Nothing happened yet
+            FingerprintCallbackHelper.State callbackState = getCallbackState(journal);
+            assertNotNull(callbackState);
+            assertEquals(0, callbackState.mNumAuthRejected);
+            assertEquals(0, callbackState.mNumAuthAccepted);
+            assertEquals(0, callbackState.mAcquiredReceived.size());
+            assertEquals(0, callbackState.mErrorsReceived.size());
+
+            // Auth and check again now
+            testSessions.first().acceptAuthentication(userId);
             mInstrumentation.waitForIdleSync();
-            Utils.waitForIdleService(this::getSensorStates);
-        }
-
-        final TestJournal journal = TestJournalContainer.get(AUTH_ON_CREATE_ACTIVITY);
-
-        // Launch test activity
-        launchActivity(AUTH_ON_CREATE_ACTIVITY);
-        mWmState.waitForActivityState(AUTH_ON_CREATE_ACTIVITY, WindowManagerState.STATE_RESUMED);
-        mInstrumentation.waitForIdleSync();
-
-        // At least one sensor should be authenticating
-        assertFalse(getSensorStates().areAllSensorsIdle());
-
-        // Nothing happened yet
-        FingerprintCallbackHelper.State callbackState = getCallbackState(journal);
-        assertNotNull(callbackState);
-        assertEquals(0, callbackState.mNumAuthRejected);
-        assertEquals(0, callbackState.mNumAuthAccepted);
-        assertEquals(0, callbackState.mAcquiredReceived.size());
-        assertEquals(0, callbackState.mErrorsReceived.size());
-
-        // Auth and check again now
-        testSessions.get(0).acceptAuthentication(userId);
-        mInstrumentation.waitForIdleSync();
-        callbackState = getCallbackState(journal);
-        assertNotNull(callbackState);
-        assertTrue(callbackState.mErrorsReceived.isEmpty());
-        assertTrue(callbackState.mAcquiredReceived.isEmpty());
-        assertEquals(1, callbackState.mNumAuthAccepted);
-        assertEquals(0, callbackState.mNumAuthRejected);
-
-        // Cleanup
-        for (BiometricTestSession session : testSessions) {
-            session.close();
+            callbackState = getCallbackState(journal);
+            assertNotNull(callbackState);
+            assertTrue(callbackState.mErrorsReceived.isEmpty());
+            assertTrue(callbackState.mAcquiredReceived.isEmpty());
+            assertEquals(1, callbackState.mNumAuthAccepted);
+            assertEquals(0, callbackState.mNumAuthRejected);
         }
     }
 
     @Test
     public void testRejectThenErrorFromForegroundActivity() throws Exception {
         assumeTrue(Utils.isFirstApiLevel29orGreater());
-        // Turn screen on and dismiss keyguard
-        UiDeviceUtils.pressWakeupButton();
-        UiDeviceUtils.pressUnlockButton();
 
         // Manually keep track and close the sessions, since we want to enroll all sensors before
         // requesting auth.
-        final List<BiometricTestSession> testSessions = new ArrayList<>();
+        final int userId = 0;
+        try (TestSessionList testSessions = createTestSessionsWithEnrollments(userId)) {
+            final TestJournal journal = TestJournalContainer.get(AUTH_ON_CREATE_ACTIVITY);
+
+            // Launch test activity
+            launchActivity(AUTH_ON_CREATE_ACTIVITY);
+            mWmState.waitForActivityState(AUTH_ON_CREATE_ACTIVITY,
+                    STATE_RESUMED);
+            mInstrumentation.waitForIdleSync();
+            FingerprintCallbackHelper.State callbackState = getCallbackState(journal);
+            assertNotNull(callbackState);
+
+            // Fingerprint rejected
+            testSessions.first().rejectAuthentication(userId);
+            mInstrumentation.waitForIdleSync();
+            callbackState = getCallbackState(journal);
+            assertNotNull(callbackState);
+            assertEquals(1, callbackState.mNumAuthRejected);
+            assertEquals(0, callbackState.mNumAuthAccepted);
+            assertEquals(0, callbackState.mAcquiredReceived.size());
+            assertEquals(0, callbackState.mErrorsReceived.size());
+
+            // Send an acquire message
+            // skip this check on devices with UDFPS because they prompt to try again
+            // and do not dispatch an acquired event via BiometricPrompt
+            final boolean verifyPartial = !hasUdfps();
+            if (verifyPartial) {
+                testSessions.first().notifyAcquired(userId,
+                        FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL);
+                mInstrumentation.waitForIdleSync();
+                callbackState = getCallbackState(journal);
+                assertNotNull(callbackState);
+                assertEquals(1, callbackState.mNumAuthRejected);
+                assertEquals(0, callbackState.mNumAuthAccepted);
+                assertEquals(1, callbackState.mAcquiredReceived.size());
+                assertEquals(FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL,
+                        (int) callbackState.mAcquiredReceived.get(0));
+                assertEquals(0, callbackState.mErrorsReceived.size());
+            }
+
+            // Send an error
+            testSessions.first().notifyError(userId, FINGERPRINT_ERROR_CANCELED);
+            mInstrumentation.waitForIdleSync();
+            callbackState = getCallbackState(journal);
+            assertNotNull(callbackState);
+            assertEquals(1, callbackState.mNumAuthRejected);
+            assertEquals(0, callbackState.mNumAuthAccepted);
+            if (verifyPartial) {
+                assertEquals(1, callbackState.mAcquiredReceived.size());
+                assertEquals(FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL,
+                        (int) callbackState.mAcquiredReceived.get(0));
+            } else {
+                assertEquals(0, callbackState.mAcquiredReceived.size());
+            }
+            assertEquals(1, callbackState.mErrorsReceived.size());
+            assertEquals(FINGERPRINT_ERROR_CANCELED,
+                    (int) callbackState.mErrorsReceived.get(0));
+
+            // Authentication lifecycle is done
+            assertTrue(getSensorStates().areAllSensorsIdle());
+        }
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 214261879)
+    public void testAuthCancelsWhenAppSwitched() throws Exception {
+        assumeTrue(Utils.isFirstApiLevel29orGreater());
 
         final int userId = 0;
+        try (TestSessionList testSessions = createTestSessionsWithEnrollments(userId)) {
+            launchActivity(AUTH_ON_CREATE_ACTIVITY);
+            final UiObject2 prompt = mDevice.wait(
+                    Until.findObject(SELECTOR_BIOMETRIC_PROMPT), WAIT_MS);
+            if (prompt == null) {
+                // some devices do not show a prompt (i.e. rear sensor)
+                mWmState.waitForActivityState(AUTH_ON_CREATE_ACTIVITY, STATE_RESUMED);
+            }
+            assertThat(getSensorStates().areAllSensorsIdle()).isFalse();
+
+            launchActivity(EMPTY_ACTIVITY);
+            if (prompt != null) {
+                assertThat(mDevice.wait(Until.gone(SELECTOR_BIOMETRIC_PROMPT), WAIT_MS)).isTrue();
+            } else {
+                // devices that do not show a sysui prompt may not cancel until an attempt is made
+                mWmState.waitForActivityState(EMPTY_ACTIVITY, STATE_RESUMED);
+                testSessions.first().acceptAuthentication(userId);
+                mInstrumentation.waitForIdleSync();
+            }
+            waitForIdleSensors();
+
+            final TestJournal journal = TestJournalContainer.get(AUTH_ON_CREATE_ACTIVITY);
+            FingerprintCallbackHelper.State callbackState = getCallbackState(journal);
+            assertThat(callbackState).isNotNull();
+            assertThat(callbackState.mNumAuthAccepted).isEqualTo(0);
+            assertThat(callbackState.mNumAuthRejected).isEqualTo(0);
+
+            // FingerprintUtils#isKnownErrorCode does not recognize FINGERPRINT_ERROR_USER_CANCELED
+            // so accept this error as a vendor error or the normal value
+            assertThat(callbackState.mErrorsReceived).hasSize(1);
+            assertThat(callbackState.mErrorsReceived.get(0)).isAnyOf(
+                    FINGERPRINT_ERROR_CANCELED,
+                    FINGERPRINT_ERROR_USER_CANCELED,
+                    FINGERPRINT_ERROR_VENDOR_BASE + FINGERPRINT_ERROR_USER_CANCELED);
+
+            assertThat(getSensorStates().areAllSensorsIdle()).isTrue();
+        }
+    }
+
+    private TestSessionList createTestSessionsWithEnrollments(int userId) {
+        final TestSessionList testSessions = new TestSessionList(this);
         for (SensorProperties prop : mSensorProperties) {
             BiometricTestSession session =
                     mFingerprintManager.createTestSession(prop.getSensorId());
@@ -250,76 +342,13 @@
 
             session.startEnroll(userId);
             mInstrumentation.waitForIdleSync();
-            Utils.waitForIdleService(this::getSensorStates);
+            waitForIdleSensors();
 
             session.finishEnroll(userId);
             mInstrumentation.waitForIdleSync();
-            Utils.waitForIdleService(this::getSensorStates);
+            waitForIdleSensors();
         }
-
-        final TestJournal journal = TestJournalContainer.get(AUTH_ON_CREATE_ACTIVITY);
-
-        // Launch test activity
-        launchActivity(AUTH_ON_CREATE_ACTIVITY);
-        mWmState.waitForActivityState(AUTH_ON_CREATE_ACTIVITY, WindowManagerState.STATE_RESUMED);
-        mInstrumentation.waitForIdleSync();
-        FingerprintCallbackHelper.State callbackState = getCallbackState(journal);
-        assertNotNull(callbackState);
-
-        // Fingerprint rejected
-        testSessions.get(0).rejectAuthentication(userId);
-        mInstrumentation.waitForIdleSync();
-        callbackState = getCallbackState(journal);
-        assertNotNull(callbackState);
-        assertEquals(1, callbackState.mNumAuthRejected);
-        assertEquals(0, callbackState.mNumAuthAccepted);
-        assertEquals(0, callbackState.mAcquiredReceived.size());
-        assertEquals(0, callbackState.mErrorsReceived.size());
-
-        // Send an acquire message
-        // skip this check on devices with UDFPS because they prompt to try again
-        // and do not dispatch an acquired event via BiometricPrompt
-        final boolean verifyPartial = !hasUdfps();
-        if (verifyPartial) {
-            testSessions.get(0).notifyAcquired(userId,
-                    FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL);
-            mInstrumentation.waitForIdleSync();
-            callbackState = getCallbackState(journal);
-            assertNotNull(callbackState);
-            assertEquals(1, callbackState.mNumAuthRejected);
-            assertEquals(0, callbackState.mNumAuthAccepted);
-            assertEquals(1, callbackState.mAcquiredReceived.size());
-            assertEquals(FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL,
-                    (int) callbackState.mAcquiredReceived.get(0));
-            assertEquals(0, callbackState.mErrorsReceived.size());
-        }
-
-        // Send an error
-        testSessions.get(0).notifyError(userId,
-                FingerprintManager.FINGERPRINT_ERROR_CANCELED);
-        mInstrumentation.waitForIdleSync();
-        callbackState = getCallbackState(journal);
-        assertNotNull(callbackState);
-        assertEquals(1, callbackState.mNumAuthRejected);
-        assertEquals(0, callbackState.mNumAuthAccepted);
-        if (verifyPartial) {
-            assertEquals(1, callbackState.mAcquiredReceived.size());
-            assertEquals(FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL,
-                    (int) callbackState.mAcquiredReceived.get(0));
-        } else {
-            assertEquals(0, callbackState.mAcquiredReceived.size());
-        }
-        assertEquals(1, callbackState.mErrorsReceived.size());
-        assertEquals(FingerprintManager.FINGERPRINT_ERROR_CANCELED,
-                (int) callbackState.mErrorsReceived.get(0));
-
-        // Authentication lifecycle is done
-        assertTrue(getSensorStates().areAllSensorsIdle());
-
-        // Cleanup
-        for (BiometricTestSession session : testSessions) {
-            session.close();
-        }
+        return testSessions;
     }
 
     private boolean hasUdfps() throws Exception {
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/util/Components.java b/tests/framework/base/biometrics/src/android/server/biometrics/util/Components.java
new file mode 100644
index 0000000..5b232e5
--- /dev/null
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/util/Components.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.biometrics.util;
+
+import android.content.ComponentName;
+import android.server.wm.component.ComponentsBase;
+
+public class Components extends ComponentsBase {
+    public static final ComponentName EMPTY_ACTIVITY = component("EmptyActivity");
+
+    private static ComponentName component(String className) {
+        return component(Components.class, className);
+    }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
index 6ef3ddc..083e72c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
@@ -102,12 +102,9 @@
         AtomicLong transitionStartTime = new AtomicLong();
         AtomicLong transitionEndTime = new AtomicLong();
 
-        final ActivityOptions.OnAnimationStartedListener startedListener = () -> {
-            transitionStartTime.set(SystemClock.elapsedRealtime());
-        };
-
-        final ActivityOptions.OnAnimationFinishedListener finishedListener = () -> {
-            transitionEndTime.set(SystemClock.elapsedRealtime());
+        final ActivityOptions.OnAnimationStartedListener startedListener = transitionStartTime::set;
+        final ActivityOptions.OnAnimationFinishedListener finishedListener = (t) -> {
+            transitionEndTime.set(t);
             latch.countDown();
         };
 
@@ -139,12 +136,9 @@
         AtomicLong transitionStartTime = new AtomicLong();
         AtomicLong transitionEndTime = new AtomicLong();
 
-        final ActivityOptions.OnAnimationStartedListener startedListener = () -> {
-            transitionStartTime.set(SystemClock.elapsedRealtime());
-        };
-
-        final ActivityOptions.OnAnimationFinishedListener finishedListener = () -> {
-            transitionEndTime.set(SystemClock.elapsedRealtime());
+        final ActivityOptions.OnAnimationStartedListener startedListener = transitionStartTime::set;
+        final ActivityOptions.OnAnimationFinishedListener finishedListener = (t) -> {
+            transitionEndTime.set(t);
             latch.countDown();
         };
 
@@ -174,12 +168,9 @@
         AtomicLong transitionStartTime = new AtomicLong();
         AtomicLong transitionEndTime = new AtomicLong();
 
-        final ActivityOptions.OnAnimationStartedListener startedListener = () -> {
-            transitionStartTime.set(SystemClock.elapsedRealtime());
-        };
-
-        final ActivityOptions.OnAnimationFinishedListener finishedListener = () -> {
-            transitionEndTime.set(SystemClock.elapsedRealtime());
+        final ActivityOptions.OnAnimationStartedListener startedListener = transitionStartTime::set;
+        final ActivityOptions.OnAnimationFinishedListener finishedListener = (t) -> {
+            transitionEndTime.set(t);
             latch.countDown();
         };
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java
index 633fa27..449f28a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java
@@ -956,7 +956,7 @@
             @AnimRes int enterAnim, @AnimRes int exitAnim) {
         ConditionVariable animationsStarted = new ConditionVariable(false);
         ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, enterAnim, exitAnim,
-                0, mMainHandler, animationsStarted::open, /* finishedListener */ null);
+                0, mMainHandler, (t) -> animationsStarted.open(), /* finishedListener */ null);
         // We're testing the opacity coming from the animation here, not the one declared in the
         // activity, so we set its opacity to 1
         addActivityOverlay(packageName, /* opacity */ 1, touchable, options.toBundle());
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
index 87cd773..c5ef7d0 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
@@ -53,12 +53,15 @@
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresPermission;
 
 import com.android.compatibility.common.util.PollingCheck;
 
 import org.junit.AssumptionViolatedException;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -85,6 +88,8 @@
 
     private final HandlerThread mHandlerThread = new HandlerThread("EventReceiver");
 
+    private final List<Intent> mStickyBroadcasts = new ArrayList<>();
+
     private static final class EventStore {
         private static final int INITIAL_ARRAY_SIZE = 32;
 
@@ -319,6 +324,9 @@
     public void close() throws Exception {
         mActive.set(false);
 
+        mStickyBroadcasts.forEach(mContext::removeStickyBroadcast);
+        mStickyBroadcasts.clear();
+
         executeShellCommand(mUiAutomation, "ime reset");
 
         PollingCheck.check("Make sure that MockIME becomes unavailable", TIMEOUT, () ->
@@ -345,14 +353,43 @@
     private ImeCommand callCommandInternal(@NonNull String commandName, @NonNull Bundle params) {
         final ImeCommand command = new ImeCommand(
                 commandName, SystemClock.elapsedRealtimeNanos(), true, params);
+        final Intent intent = createCommandIntent(command);
+        mContext.sendBroadcast(intent);
+        return command;
+    }
+
+    /**
+     * A variant of {@link #callCommandInternal} that uses
+     * {@link Context#sendStickyBroadcast(android.content.Intent) sendStickyBroadcast} to ensure
+     * that the command is received even if the IME is not running at the time of sending
+     * (e.g. when {@code config_preventImeStartupUnlessTextEditor} is set).
+     * <p>
+     * The caller requires the {@link android.Manifest.permission#BROADCAST_STICKY BROADCAST_STICKY}
+     * permission.
+     */
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
+    private ImeCommand callCommandInternalSticky(
+            @NonNull String commandName,
+            @NonNull Bundle params) {
+        final ImeCommand command = new ImeCommand(
+                commandName, SystemClock.elapsedRealtimeNanos(), true, params);
+        final Intent intent = createCommandIntent(command);
+        mStickyBroadcasts.add(intent);
+        mContext.sendStickyBroadcast(intent);
+        return command;
+    }
+
+    @NonNull
+    private Intent createCommandIntent(@NonNull ImeCommand command) {
         final Intent intent = new Intent();
         intent.setPackage(MockIme.getComponentName().getPackageName());
         intent.setAction(MockIme.getCommandActionName(mImeEventActionName));
         intent.putExtras(command.toBundle());
-        mContext.sendBroadcast(intent);
-        return command;
+        return intent;
     }
 
+
     /**
      * Lets {@link MockIme} suspend {@link MockIme.AbstractInputMethodImpl#createSession(
      * android.view.inputmethod.InputMethod.SessionCallback)} until {@link #resumeCreateSession()}.
@@ -1395,8 +1432,9 @@
     }
 
     @NonNull
+    @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
     public ImeCommand callSetInlineSuggestionsExtras(@NonNull Bundle bundle) {
-        return callCommandInternal("setInlineSuggestionsExtras", bundle);
+        return callCommandInternalSticky("setInlineSuggestionsExtras", bundle);
     }
 
     @NonNull
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionEndToEndTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionEndToEndTest.java
index c0e1546..9292f6a9 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionEndToEndTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionEndToEndTest.java
@@ -92,6 +92,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -363,6 +364,22 @@
     }
 
     /**
+     * A utility method to run a unit test for {@link InputConnection}.
+     *
+     * <p>This utility method enables you to avoid boilerplate code when writing unit tests for
+     * {@link InputConnection}.</p>
+     *
+     * @param inputConnectionWrapperProvider {@link Function} to install custom hooks to the
+     *                                       original {@link InputConnection}.
+     * @param testProcedure Test body.
+     */
+    private void testInputConnection(
+            Function<InputConnection, InputConnection> inputConnectionWrapperProvider,
+            TestProcedureForMixedImes testProcedure) throws Exception {
+        testInputConnection(inputConnectionWrapperProvider, testProcedure, null);
+    }
+
+    /**
      * A utility method to run a unit test for {@link InputConnection} with
      * {@link android.accessibilityservice.InputMethod}.
      *
@@ -2607,6 +2624,75 @@
     }
 
     /**
+     * Test {@link android.accessibilityservice.InputMethod.AccessibilityInputConnection#commitText(
+     * CharSequence, int, TextAttribute)} finishes any existing composing text.
+     */
+    @Test
+    public void testCommitTextFromA11yFinishesExistingComposition() throws Exception {
+        final MethodCallVerifier endBatchEditVerifier = new MethodCallVerifier();
+        final CopyOnWriteArrayList<String> callHistory = new CopyOnWriteArrayList<>();
+
+        final class Wrapper extends InputConnectionWrapper {
+            private int mBatchEditCount = 0;
+
+            private Wrapper(InputConnection target) {
+                super(target, false);
+            }
+
+            @Override
+            public boolean setComposingText(CharSequence text, int newCursorPosition,
+                    TextAttribute textAttribute) {
+                callHistory.add("setComposingText");
+                return true;
+            }
+
+            @Override
+            public boolean beginBatchEdit() {
+                callHistory.add("beginBatchEdit");
+                ++mBatchEditCount;
+                return true;
+            }
+
+            @Override
+            public boolean finishComposingText() {
+                callHistory.add("finishComposingText");
+                return true;
+            }
+
+            @Override
+            public boolean commitText(
+                    CharSequence text, int newCursorPosition, TextAttribute textAttribute) {
+                callHistory.add("commitText");
+                return true;
+            }
+
+            @Override
+            public boolean endBatchEdit() {
+                callHistory.add("endBatchEdit");
+                --mBatchEditCount;
+                final boolean batchEditStillInProgress = mBatchEditCount > 0;
+                if (!batchEditStillInProgress) {
+                    endBatchEditVerifier.onMethodCalled(args -> { });
+                }
+                return batchEditStillInProgress;
+            }
+        }
+
+        testInputConnection(Wrapper::new, (imeSession, imeStream, a11ySession, a11yStream) -> {
+            expectCommand(imeStream, imeSession.callSetComposingText("fromIme", 1, null), TIMEOUT);
+            expectA11yImeCommand(a11yStream, a11ySession.callCommitText("fromA11y", 1, null),
+                    TIMEOUT);
+            endBatchEditVerifier.expectCalledOnce(args -> { }, TIMEOUT);
+            assertThat(callHistory).containsExactly(
+                    "setComposingText",
+                    "beginBatchEdit",
+                    "finishComposingText",
+                    "commitText",
+                    "endBatchEdit").inOrder();
+        });
+    }
+
+    /**
      * Test {@link InputConnection#setComposingText(CharSequence, int)} works as expected.
      */
     @Test
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index 771739b..3591ffa 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -104,6 +104,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -336,6 +338,40 @@
     }
 
     @Test
+    public void testShowHideKeyboardWithInterval() throws Exception {
+        final InputMethodManager imm = InstrumentationRegistry.getInstrumentation()
+                .getTargetContext().getSystemService(InputMethodManager.class);
+
+        try (MockImeSession imeSession = MockImeSession.create(
+                InstrumentationRegistry.getInstrumentation().getContext(),
+                InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+                new ImeSettings.Builder())) {
+            final ImeEventStream stream = imeSession.openEventStream();
+            final String marker = getTestMarker();
+            final EditText editText = launchTestActivity(marker);
+            expectImeInvisible(TIMEOUT);
+
+            runOnMainSync(() -> imm.showSoftInput(editText, 0));
+            expectEvent(stream, editorMatcher("onStartInputView", marker), TIMEOUT);
+            expectImeVisible(TIMEOUT);
+
+            // Intervals = 10, 20, 30, ..., 100, 150, 200, ...
+            final List<Integer> intervals = new ArrayList<>();
+            for (int i = 10; i < 100; i += 10) intervals.add(i);
+            for (int i = 100; i < 500; i += 50) intervals.add(i);
+            // Regression test for b/221483132.
+            // WindowInsetsController tries to clean up IME window after IME hide animation is done.
+            // Makes sure that IMM#showSoftInput during IME hide animation cancels the cleanup.
+            for (int intervalMillis : intervals) {
+                runOnMainSync(() -> imm.hideSoftInputFromWindow(editText.getWindowToken(), 0));
+                SystemClock.sleep(intervalMillis);
+                runOnMainSync(() -> imm.showSoftInput(editText, 0));
+                expectImeVisible(TIMEOUT, "IME should be visible. Interval = " + intervalMillis);
+            }
+        }
+    }
+
+    @Test
     public void testShowSoftInputWithShowForcedFlagWhenAppIsLeaving() throws Exception {
         final InputMethodManager imm = InstrumentationRegistry.getInstrumentation()
                 .getTargetContext().getSystemService(InputMethodManager.class);
diff --git a/tests/inputmethod/util/src/android/view/inputmethod/cts/util/InputMethodVisibilityVerifier.java b/tests/inputmethod/util/src/android/view/inputmethod/cts/util/InputMethodVisibilityVerifier.java
index c04035a..0185cd8 100644
--- a/tests/inputmethod/util/src/android/view/inputmethod/cts/util/InputMethodVisibilityVerifier.java
+++ b/tests/inputmethod/util/src/android/view/inputmethod/cts/util/InputMethodVisibilityVerifier.java
@@ -102,6 +102,17 @@
     }
 
     /**
+     * Asserts that {@link com.android.cts.mockime.MockIme} is visible to the user.
+     *
+     * @param timeout timeout in milliseconds.
+     * @param message error message shown on failure.
+     * @see #expectImeVisible(long)
+     */
+    public static void expectImeVisible(long timeout, String message) {
+        assertTrue(message, waitUntil(timeout, InputMethodVisibilityVerifier::containsWatermark));
+    }
+
+    /**
      * Asserts that {@link com.android.cts.mockime.MockIme} is not visible to the user.
      *
      * <p>This always succeeds when
diff --git a/tests/quickaccesswallet/AndroidTest.xml b/tests/quickaccesswallet/AndroidTest.xml
index 98876d7..bc25c3c 100644
--- a/tests/quickaccesswallet/AndroidTest.xml
+++ b/tests/quickaccesswallet/AndroidTest.xml
@@ -30,6 +30,7 @@
         <option name="test-file-name" value="CtsQuickAccessWalletTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.quickaccesswallet.cts" />
+       <option name="package" value="android.quickaccesswallet.cts" />
+       <option name="test-timeout" value="300000" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
index c16bd04..2bc63f7 100644
--- a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
+++ b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
@@ -19,10 +19,9 @@
 import android.app.Instrumentation;
 import android.signature.cts.ApiComplianceChecker;
 import android.signature.cts.ApiDocumentParser;
+import android.signature.cts.JDiffClassDescription;
 import android.signature.cts.VirtualPath;
-import android.signature.cts.VirtualPath.LocalFilePath;
 import androidx.test.platform.app.InstrumentationRegistry;
-import java.io.IOException;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.TreeSet;
@@ -61,6 +60,21 @@
     }
 
     /**
+     * Return a stream of {@link JDiffClassDescription} that are expected to be provided by the
+     * shared libraries which are installed on this device.
+     *
+     * @param apiDocumentParser the parser to use.
+     * @param apiResources the list of API resource files.
+     * @return a stream of {@link JDiffClassDescription}.
+     */
+    private Stream<JDiffClassDescription> parseActiveSharedLibraryApis(
+            ApiDocumentParser apiDocumentParser, String[] apiResources) {
+        return retrieveApiResourcesAsStream(getClass().getClassLoader(), apiResources)
+                .filter(this::checkLibrary)
+                .flatMap(apiDocumentParser::parseAsStream);
+    }
+
+    /**
      * Tests that the device's API matches the expected set defined in xml.
      * <p/>
      * Will check the entire API, and then report the complete list of failures
@@ -73,7 +87,7 @@
 
             ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-            parseApiResourcesAsStream(apiDocumentParser, expectedApiFiles)
+            parseActiveSharedLibraryApis(apiDocumentParser, expectedApiFiles)
                     .forEach(complianceChecker::checkSignatureCompliance);
 
             // After done parsing all expected API files, perform any deferred checks.
@@ -92,7 +106,7 @@
 
             ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-            parseApiResourcesAsStream(apiDocumentParser, previousApiFiles)
+            parseActiveSharedLibraryApis(apiDocumentParser, previousApiFiles)
                     .map(clazz -> clazz.setPreviousApiFlag(true))
                     .forEach(complianceChecker::checkSignatureCompliance);
 
@@ -105,10 +119,11 @@
      * Check to see if the supplied name is an API file for a shared library that is available on
      * this device.
      *
-     * @param name the name of the possible API file for a shared library.
-     * @return true if it is, false otherwise.
+     * @param path the path of the API file.
+     * @return true if the API corresponds to a shared library on the device, false otherwise.
      */
-    private boolean checkLibrary (String name) {
+    private boolean checkLibrary (VirtualPath path) {
+        String name = path.toString();
         String libraryName = name.substring(name.lastIndexOf('/') + 1).split("-")[0];
         boolean matched = libraries.contains(libraryName);
         if (matched) {
@@ -122,19 +137,4 @@
         }
         return matched;
     }
-
-    /**
-     * Override the method that gets the files from a supplied zip file to filter out any file that
-     * does not correspond to a shared library available on the device.
-     *
-     * @param path the path to the zip file.
-     * @return a stream of paths in the zip file that contain APIs that should be available to this
-     * tests.
-     * @throws IOException if there was an issue reading the zip file.
-     */
-    @Override
-    protected Stream<VirtualPath> getZipEntryFiles(LocalFilePath path) throws IOException {
-        // Only return entries corresponding to shared libraries.
-        return super.getZipEntryFiles(path).filter(p -> checkLibrary(p.toString()));
-    }
 }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
index 5bfe0bb..f4d364b 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
@@ -41,6 +41,7 @@
 import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.function.Predicate;
 import java.util.stream.Stream;
 import java.util.zip.ZipFile;
 import org.junit.Before;
@@ -191,10 +192,10 @@
         return argument.split(",");
     }
 
-    private Stream<VirtualPath> readResource(String resourceName) {
+    private static Stream<VirtualPath> readResource(ClassLoader classLoader, String resourceName) {
         try {
             ResourcePath resourcePath =
-                    VirtualPath.get(getClass().getClassLoader(), resourceName);
+                    VirtualPath.get(classLoader, resourceName);
             if (resourceName.endsWith(".zip")) {
                 // Extract to a temporary file and read from there.
                 Path file = extractResourceToFile(resourceName, resourcePath.newInputStream());
@@ -207,7 +208,7 @@
         }
     }
 
-    Path extractResourceToFile(String resourceName, InputStream is) throws IOException {
+    private static Path extractResourceToFile(String resourceName, InputStream is) throws IOException {
         Path tempDirectory = Files.createTempDirectory("signature");
         Path file = tempDirectory.resolve(resourceName);
         Log.i(TAG, "extractResourceToFile: extracting " + resourceName + " to " + file);
@@ -220,7 +221,7 @@
      * Given a path in the local file system (possibly of a zip file) flatten it into a stream of
      * virtual paths.
      */
-    private Stream<VirtualPath> flattenPaths(LocalFilePath path) {
+    private static Stream<VirtualPath> flattenPaths(LocalFilePath path) {
         try {
             if (path.toString().endsWith(".zip")) {
                 return getZipEntryFiles(path);
@@ -232,20 +233,46 @@
         }
     }
 
+    /**
+     * Create a stream of {@link JDiffClassDescription} by parsing a set of API resource files.
+     *
+     * @param apiDocumentParser the parser to use.
+     * @param apiResources the list of API resource files.
+     *
+     * @return the stream of {@link JDiffClassDescription}.
+     */
     Stream<JDiffClassDescription> parseApiResourcesAsStream(
             ApiDocumentParser apiDocumentParser, String[] apiResources) {
-        return Stream.of(apiResources)
-                .flatMap(this::readResource)
+        return retrieveApiResourcesAsStream(getClass().getClassLoader(), apiResources)
                 .flatMap(apiDocumentParser::parseAsStream);
     }
 
     /**
+     * Retrieve a stream of {@link VirtualPath} from a list of API resource files.
+     *
+     * <p>Any zip files are flattened, i.e. if a resource name ends with {@code .zip} then it is
+     * unpacked into a temporary directory and the paths to the unpacked files are returned instead
+     * of the path to the zip file.</p>
+     *
+     * @param classLoader the {@link ClassLoader} from which the resources will be loaded.
+     * @param apiResources the list of API resource files.
+     *
+     * @return the stream of {@link VirtualPath}.
+     */
+    static Stream<VirtualPath> retrieveApiResourcesAsStream(
+            ClassLoader classLoader,
+            String[] apiResources) {
+        return Stream.of(apiResources)
+                .flatMap(resourceName -> readResource(classLoader, resourceName));
+    }
+
+    /**
      * Get the zip entries that are files.
      *
      * @param path the path to the zip file.
      * @return paths to zip entries
      */
-    protected Stream<VirtualPath> getZipEntryFiles(LocalFilePath path) throws IOException {
+    private static Stream<VirtualPath> getZipEntryFiles(LocalFilePath path) throws IOException {
         @SuppressWarnings("resource")
         ZipFile zip = new ZipFile(path.toFile());
         return zip.stream().map(entry -> VirtualPath.get(zip, entry));
diff --git a/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java b/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
index efd574e..ddbc1d5 100644
--- a/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
+++ b/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
@@ -91,6 +91,12 @@
 
             for (String activeIntent : activeIntents) {
               String intent = activeIntent.trim();
+
+                // STOPSHIP Remove this. b/230099874
+                if ("android.intent.action.EXPERIMENTAL_IS_ALIAS".equals(intent)) {
+                    continue;
+                }
+
               if (!platformIntents.contains(intent) &&
                     intent.startsWith(ANDROID_INTENT_PREFIX)) {
                   invalidIntents.add(activeIntent);
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
index bb4e6e3..0f1599d 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
@@ -36,6 +36,7 @@
 import android.app.AppOpsManager.MODE_ERRORED
 import android.app.AppOpsManager.MODE_IGNORED
 import android.app.AppOpsManager.OnOpChangedListener
+import android.app.AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS
 import android.app.AppOpsManager.OPSTR_FINE_LOCATION
 import android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA
 import android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE
@@ -51,6 +52,7 @@
 import android.platform.test.annotations.AppModeFull
 import androidx.test.runner.AndroidJUnit4
 import androidx.test.InstrumentationRegistry
+import org.junit.Assert
 
 import org.junit.Before
 import org.junit.Test
@@ -608,6 +610,57 @@
         assertEquals(MODE_IGNORED, cameraReturn)
     }
 
+    @Test
+    fun testRestrictedSettingsOpsRead() {
+        // Apps without manage appops permission will get security exception if it tries to access
+        // restricted settings ops.
+        Assert.assertThrows(SecurityException::class.java) {
+            mAppOps.unsafeCheckOpRawNoThrow(OPSTR_ACCESS_RESTRICTED_SETTINGS, Process.myUid(),
+                    mOpPackageName)
+        }
+        // Apps with manage appops permission (shell) should be able to read restricted settings op
+        // successfully.
+        runWithShellPermissionIdentity {
+            mAppOps.unsafeCheckOpRawNoThrow(OPSTR_ACCESS_RESTRICTED_SETTINGS, Process.myUid(),
+                    mOpPackageName)
+        }
+
+        // Normal apps should not receive op change callback when op is changed.
+        val watcher = mock(OnOpChangedListener::class.java)
+        try {
+            setOpMode(mOpPackageName, OPSTR_ACCESS_RESTRICTED_SETTINGS, MODE_ERRORED)
+
+            mAppOps.startWatchingMode(OPSTR_ACCESS_RESTRICTED_SETTINGS, mOpPackageName, watcher)
+
+            // Make a change to the app op's mode.
+            Mockito.reset(watcher)
+            setOpMode(mOpPackageName, OPSTR_ACCESS_RESTRICTED_SETTINGS, MODE_ALLOWED)
+            verifyZeroInteractions(watcher)
+        } finally {
+            // Clean up registered watcher.
+            mAppOps.stopWatchingMode(watcher)
+        }
+
+        // Apps with manage ops permission (shell) should be able to receive op change callback.
+        runWithShellPermissionIdentity {
+            try {
+                setOpMode(mOpPackageName, OPSTR_ACCESS_RESTRICTED_SETTINGS, MODE_ERRORED)
+
+                mAppOps.startWatchingMode(OPSTR_ACCESS_RESTRICTED_SETTINGS, mOpPackageName,
+                        watcher)
+
+                // Make a change to the app op's mode.
+                Mockito.reset(watcher)
+                setOpMode(mOpPackageName, OPSTR_ACCESS_RESTRICTED_SETTINGS, MODE_ALLOWED)
+                verify(watcher, timeout(TIMEOUT_MS))
+                        .onOpChanged(OPSTR_ACCESS_RESTRICTED_SETTINGS, mOpPackageName)
+            } finally {
+                // Clean up registered watcher.
+                mAppOps.stopWatchingMode(watcher)
+            }
+        }
+    }
+
     private fun runWithShellPermissionIdentity(command: () -> Unit) {
         val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation()
         uiAutomation.adoptShellPermissionIdentity()
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
index 8fcd24d..80f4bbd 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
@@ -102,8 +102,8 @@
         Parcel out = Parcel.obtain();
         out.writeInt(presetIndex);
         out.writeString(presetName);
-        out.writeBoolean(isAvailable);
         out.writeBoolean(isWritable);
+        out.writeBoolean(isAvailable);
         out.setDataPosition(0); // reset position of parcel before passing to constructor
         return BluetoothHapPresetInfo.CREATOR.createFromParcel(out);
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
index 0153953..b40b52d 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
@@ -48,7 +48,7 @@
     // See Page 5 of Generic Audio assigned number specification
     private static final byte[] TEST_METADATA_BYTES = {
             // length = 0x05, type = 0x03, value = 0x00000001 (front left)
-            0x05, 0x03, 0x00, 0x00, 0x00, 0x01
+            0x05, 0x03, 0x01, 0x00, 0x00, 0x00
     };
 
     private Context mContext;
@@ -126,7 +126,7 @@
                 new BluetoothLeAudioCodecConfigMetadata.Builder(codecMetadata).build();
         assertEquals(codecMetadata, codecMetadataCopy);
         assertEquals(TEST_AUDIO_LOCATION_FRONT_LEFT, codecMetadataCopy.getAudioLocation());
-        assertArrayEquals(TEST_METADATA_BYTES, codecMetadata.getRawMetadata());
+        assertArrayEquals(codecMetadata.getRawMetadata(), codecMetadataCopy.getRawMetadata());
     }
 
     @Test
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java b/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
index a45a377..8667328 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
@@ -83,14 +83,14 @@
             case BluetoothProfile.HID_HOST:
                 return BluetoothProperties.isProfileHidHostEnabled().orElse(false);
             case BluetoothProfile.LE_AUDIO:
-                return BluetoothProperties.isProfileBapUnicastServerEnabled().orElse(false);
+                return BluetoothProperties.isProfileBapUnicastClientEnabled().orElse(false);
             case BluetoothProfile.LE_AUDIO_BROADCAST:
                 return BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false);
             case BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT:
                 return BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false);
             // Hidden profile
             // case BluetoothProfile.LE_CALL_CONTROL:
-            //     return BluetoothProperties.isProfileTbsServerEnabled().orElse(false);
+            //     return BluetoothProperties.isProfileCcpServerEnabled().orElse(false);
             case BluetoothProfile.MAP:
                 return BluetoothProperties.isProfileMapServerEnabled().orElse(false);
             case BluetoothProfile.MAP_CLIENT:
@@ -110,7 +110,7 @@
             case BluetoothProfile.SAP:
                 return BluetoothProperties.isProfileSapServerEnabled().orElse(false);
             case BluetoothProfile.VOLUME_CONTROL:
-                return BluetoothProperties.isProfileVcServerEnabled().orElse(false);
+                return BluetoothProperties.isProfileVcpControllerEnabled().orElse(false);
             default:
                 return false;
         }
diff --git a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
index b47e25f..3af4c95 100644
--- a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
@@ -891,6 +891,49 @@
                 }).build().verify(mCarPropertyManager);
     }
 
+    @Test
+    public void testEvChargeSwitchIfSupported() {
+        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_SWITCH,
+                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                Boolean.class).build().verify(mCarPropertyManager);
+    }
+
+    @Test
+    public void testEvChargeTimeRemainingIfSupported() {
+        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_TIME_REMAINING,
+                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                Integer.class).setCarPropertyValueVerifier(
+                (carPropertyConfig, carPropertyValue) -> {
+                    assertWithMessage(
+                            "FUEL_LEVEL Integer value must be greater than or equal 0").that(
+                            (Integer) carPropertyValue.getValue()).isAtLeast(0);
+
+                }).build().verify(mCarPropertyManager);
+    }
+
+    @Test
+    public void testEvRegenerativeBrakingStateIfSupported() {
+        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_REGENERATIVE_BRAKING_STATE,
+                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                Integer.class).setCarPropertyValueVerifier(
+                (carPropertyConfig, carPropertyValue) -> {
+                    Integer evRegenerativeBrakingState = (Integer) carPropertyValue.getValue();
+                    assertWithMessage("EV_REGENERATIVE_BRAKING_STATE must be a defined state: "
+                            + evRegenerativeBrakingState).that(evRegenerativeBrakingState).isIn(
+                            ImmutableSet.of(/*EvRegenerativeBrakingState.UNKNOWN=*/0,
+                                    /*EvRegenerativeBrakingState.DISABLED=*/1,
+                                    /*EvRegenerativeBrakingState.PARTIALLY_ENABLED=*/2,
+                                    /*EvRegenerativeBrakingState.FULLY_ENABLED=*/3));
+                }).build().verify(mCarPropertyManager);
+    }
+
+
     @SuppressWarnings("unchecked")
     @Test
     public void testGetProperty() {
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/os/SystemPropertiesHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/os/SystemPropertiesHelperTest.java
index 9b915f3..2bebd3d 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/os/SystemPropertiesHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/os/SystemPropertiesHelperTest.java
@@ -16,11 +16,9 @@
 
 package android.car.cts.builtin.os;
 
-import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
 
 import android.car.builtin.os.SystemPropertiesHelper;
-import android.os.SystemProperties;
-import android.util.Log;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -31,15 +29,17 @@
 public final class SystemPropertiesHelperTest {
     private static final String TAG = SystemPropertiesHelperTest.class.getSimpleName();
 
-    // a temporary SystemProperty for CTS. it will be cleared after device reboot.
-    private static final String CTS_TEST_PROPERTY_KEY = "cts.car.builtin_property_helper.String";
+    // a temporary SystemProperty for CTS.
+    private static final String CTS_TEST_PROPERTY_KEY = "dev.android.car.test.cts.builtin_test";
     private static final String CTS_TEST_PROPERTY_VAL = "SystemPropertiesHelperTest";
 
     @Test
-    public void testSet() {
-        SystemPropertiesHelper.set(CTS_TEST_PROPERTY_KEY, CTS_TEST_PROPERTY_VAL);
-        String val = SystemProperties.get(CTS_TEST_PROPERTY_KEY);
-        Log.d(TAG, val);
-        assertThat(val).isEqualTo(CTS_TEST_PROPERTY_VAL);
+    public void testSet_throwsException() {
+        // system properties are protected by SELinux policies. Though properties with "dev."
+        // prefix are accessible via the shell domain and car shell (carservice_app) domain,
+        // they are not accessible via CTS. The java RuntimeException is expected due to access
+        // permission deny.
+        assertThrows(RuntimeException.class,
+                () -> SystemPropertiesHelper.set(CTS_TEST_PROPERTY_KEY, CTS_TEST_PROPERTY_VAL));
     }
 }
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/util/AssistUtilsHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/util/AssistUtilsHelperTest.java
index eb5b0e9..a08e050 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/util/AssistUtilsHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/util/AssistUtilsHelperTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.app.Instrumentation;
 import android.car.builtin.util.AssistUtilsHelper;
 import android.content.Context;
@@ -59,7 +61,10 @@
     @Test
     public void testOnShownCallback() throws Exception {
         SessionShowCallbackHelperImpl callbackHelperImpl = new SessionShowCallbackHelperImpl();
-        AssistUtilsHelper.showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        boolean isAssistantComponentAvailable = AssistUtilsHelper
+                .showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        assumeTrue(isAssistantComponentAvailable);
+
         callbackHelperImpl.waitForCallback();
 
         assertWithMessage("Voice session shown")
@@ -77,7 +82,10 @@
     @Test
     public void isSessionRunning_whenSessionIsShown_succeeds() throws Exception {
         SessionShowCallbackHelperImpl callbackHelperImpl = new SessionShowCallbackHelperImpl();
-        AssistUtilsHelper.showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        boolean isAssistantComponentAvailable = AssistUtilsHelper
+                .showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        assumeTrue(isAssistantComponentAvailable);
+
         callbackHelperImpl.waitForCallback();
 
         assertWithMessage("Voice interaction session running")
@@ -92,7 +100,10 @@
         AssistUtilsHelper.registerVoiceInteractionSessionListenerHelper(mContext, listener);
 
         SessionShowCallbackHelperImpl callbackHelperImpl = new SessionShowCallbackHelperImpl();
-        AssistUtilsHelper.showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        boolean isAssistantComponentAvailable = AssistUtilsHelper
+                .showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        assumeTrue(isAssistantComponentAvailable);
+
         callbackHelperImpl.waitForCallback();
 
         listener.waitForSessionChange();
@@ -110,7 +121,10 @@
         AssistUtilsHelper.registerVoiceInteractionSessionListenerHelper(mContext, listener);
 
         SessionShowCallbackHelperImpl callbackHelperImpl = new SessionShowCallbackHelperImpl();
-        AssistUtilsHelper.showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        boolean isAssistantComponentAvailable = AssistUtilsHelper
+                .showPushToTalkSessionForActiveService(mContext, callbackHelperImpl);
+        assumeTrue(isAssistantComponentAvailable);
+
         callbackHelperImpl.waitForCallback();
 
         listener.waitForSessionChange();
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index ffe417c..90aa734 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -1217,7 +1217,10 @@
             onBroadcastThread.set(thread);
         });
 
-        onBroadcastThread.get().join();
+        final Thread thread = onBroadcastThread.get();
+        if (thread != null) {
+            thread.join();
+        }
     }
 
     private void runPackageVerifierTestSync(String expectedResultStartsWith,
diff --git a/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java b/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
index 98de3ee..dcd6855 100644
--- a/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
@@ -311,7 +311,7 @@
 
     private static class RemoteTest implements AutoCloseable {
         private static final int SPIN_SLEEP_MS = 500;
-        private static final long RESPONSE_TIMEOUT_MS = 60 * 1000;
+        private static final long RESPONSE_TIMEOUT_MS = 120 * 1000;
 
         private final ShellInstallSession mSession;
         private final String mTestName;
diff --git a/tests/tests/media/common/src/android/media/cts/MediaStubActivity.java b/tests/tests/media/common/src/android/media/cts/MediaStubActivity.java
index fc5d459..541c68f 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaStubActivity.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaStubActivity.java
@@ -15,25 +15,41 @@
  */
 package android.media.cts;
 
-import android.media.cts.R;
-
 import android.app.Activity;
+import android.content.Intent;
+import android.media.cts.R;
+import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.Window;
+import android.view.WindowInsets;
+import android.view.WindowInsetsController;
 import android.view.WindowManager;
 
+import androidx.test.filters.SdkSuppress;
+
+import com.android.compatibility.common.util.ApiLevelUtil;
+
 public class MediaStubActivity extends Activity {
     private static final String TAG = "MediaStubActivity";
     private SurfaceHolder mHolder;
     private SurfaceHolder mHolder2;
 
+    public static final String INTENT_EXTRA_NO_TITLE = "NoTitle";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R)) {
+            Intent intent = getIntent();
+            if (intent.getBooleanExtra(INTENT_EXTRA_NO_TITLE, false)) {
+                hideTitle();
+            }
+        }
         setTurnScreenOn(true);
         setShowWhenLocked(true);
 
@@ -64,4 +80,26 @@
     public SurfaceHolder getSurfaceHolder2() {
         return mHolder2;
     }
+
+    /** Note: Must be called from the thread used to create this activity. */
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
+    public void hideSystemBars() {
+        var surfaceV = (SurfaceView)findViewById(R.id.surface);
+        WindowInsetsController windowInsetsController = surfaceV.getWindowInsetsController();
+        if (windowInsetsController == null) {
+            return;
+        }
+        // Configure the behavior of the hidden system bars
+        windowInsetsController.setSystemBarsBehavior(
+                WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
+        // Hide both the status bar and the navigation bar
+        windowInsetsController.hide(WindowInsets.Type.systemBars());
+    }
+
+    /** Note: Must be called before {@code setContentView}. */
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
+    private void hideTitle() {
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+    }
+
 }
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderPushBlankBuffersOnStopTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderPushBlankBuffersOnStopTest.java
new file mode 100644
index 0000000..394a779
--- /dev/null
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderPushBlankBuffersOnStopTest.java
@@ -0,0 +1,256 @@
+package android.media.decoder.cts;
+
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.media.cts.MediaHeavyPresubmitTest;
+import android.media.cts.MediaStubActivity;
+import android.media.cts.Preconditions;
+import android.media.MediaCodec;
+import android.media.MediaCodecList;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import android.view.Surface;
+
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.screenshot.ScreenCapture;
+import androidx.test.runner.screenshot.Screenshot;
+
+import com.android.compatibility.common.util.ApiLevelUtil;
+
+import org.junit.Test;
+import org.junit.Assert;
+import org.junit.Assume;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Class that contains tests for the "Push blank buffers on stop" decoder feature.
+ * <br>
+ * In order to detect that a blank buffer has been pushed to the {@code Surface}that the codec works
+ * on, we take a fullscreen screenshot before and after the call to {@code MediaCodec#stop}. This
+ * workaround appears necessary at the time of writing because the usual APIs to extract the content
+ * of a native {@code Surface} (such as {@code PixelCopy} or {@code ImageReader}) appear to fail for
+ * this frame specifically.
+ * <br>
+ * This test class is inspired from the {@link DecoderTest} test class, but with specific setup code
+ * to ensure the activity is launched in immersive mode and its title is removed.
+ */
+@MediaHeavyPresubmitTest
+public class DecoderPushBlankBuffersOnStopTest {
+    private static final String TAG = "DecoderPushBlankBufferOnStopTest";
+    private static final String mInpPrefix = WorkDir.getMediaDirString();
+
+    /**
+     * Retrieve a file descriptor to a test resource from its file name.
+     * @param res  Name from a resource in the media assets
+     */
+    private static AssetFileDescriptor getAssetFileDescriptorFor(final String res)
+            throws FileNotFoundException {
+        final String mediaDirPath = WorkDir.getMediaDirString();
+        File mediaFile = new File(mediaDirPath + res);
+        Preconditions.assertTestFileExists(mediaDirPath + res);
+        ParcelFileDescriptor parcelFD =
+                ParcelFileDescriptor.open(mediaFile, ParcelFileDescriptor.MODE_READ_ONLY);
+        return new AssetFileDescriptor(parcelFD, 0, parcelFD.getStatSize());
+    }
+
+    private static boolean isUniformlyBlank(Bitmap bitmap) {
+        final var color = new Color(); // Defaults to opaque black in sRGB
+        final int width = bitmap.getWidth();
+        final int height = bitmap.getHeight();
+        // Check a subset of pixels against the first pixel of the image.
+        // This is not strictly sufficient, but probably good enough and much more efficient.
+        for (int y = 0; y < height; y+=4) {
+            for (int x = 0; x < width; x+=4) {
+                if (color.toArgb() != bitmap.getColor(x, y).toArgb()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private void testPushBlankBuffersOnStop(String testVideo) throws Exception {
+        // Configure the test activity to hide its title
+        final var noTitle = new Intent(ApplicationProvider.getApplicationContext(),
+                MediaStubActivity.class);
+        noTitle.putExtra(MediaStubActivity.INTENT_EXTRA_NO_TITLE, true);
+        try(ActivityScenario<MediaStubActivity> scenario = ActivityScenario.launch(noTitle)) {
+            final var surface = new AtomicReference<Surface>();
+            scenario.onActivity(activity -> {
+                        surface.set(activity.getSurfaceHolder().getSurface());
+                    });
+
+            // Setup media extraction
+            final AssetFileDescriptor fd = getAssetFileDescriptorFor(testVideo);
+            final var extractor = new MediaExtractor();
+            extractor.setDataSource(fd);
+            fd.close();
+            MediaFormat format = null;
+            int trackIndex = -1;
+            for (int i = 0; i < extractor.getTrackCount(); i++) {
+                format = extractor.getTrackFormat(i);
+                if (format.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
+                    trackIndex = i;
+                    break;
+                }
+            }
+            Assert.assertTrue("No video track was found", trackIndex >= 0);
+            extractor.selectTrack(trackIndex);
+            // Enable PUSH_BLANK_BUFFERS_ON_STOP
+            format.setInteger(MediaFormat.KEY_PUSH_BLANK_BUFFERS_ON_STOP, 1);
+
+            // Setup video codec
+            final var mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+            final String decoderName = mcl.findDecoderForFormat(format);
+            Assume.assumeNotNull(String.format("No decoder for %s", format), format);
+            final MediaCodec decoder = MediaCodec.createByCodecName(decoderName);
+            // Boolean set from the decoding thread to signal that a frame has been decoded
+            final var displayedFrame = new AtomicBoolean(false);
+            // Lock used for thread synchronization
+            final Lock lock = new ReentrantLock();
+            // Condition that signals the decoding thread has made enough progress
+            final Condition processingDone = lock.newCondition();
+            final var cb = new MediaCodec.Callback() {
+                    /** Queue input buffers until one buffer has been decoded. */
+                    @Override
+                    public void onInputBufferAvailable(MediaCodec codec, int index) {
+                        lock.lock();
+                        try {
+                            // Stop queuing frames once a frame has been displayed
+                            if (displayedFrame.get()) {
+                                return;
+                            }
+                        } finally {
+                            lock.unlock();
+                        }
+
+                        ByteBuffer inputBuffer = codec.getInputBuffer(index);
+                        int sampleSize = extractor.readSampleData(inputBuffer,
+                                0 /* offset */);
+                        if (sampleSize < 0) {
+                            codec.queueInputBuffer(index, 0 /* offset */, 0 /* sampleSize */,
+                                    0 /* presentationTimeUs */,
+                                    MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+                            return;
+                        }
+                        final long presentationTimeMs = System.currentTimeMillis();
+                        codec.queueInputBuffer(index, 0 /* offset */, sampleSize,
+                                presentationTimeMs * 1000, 0 /* flags */);
+                        extractor.advance();
+                    }
+
+                    /** Render the output buffer and signal that the processing is done. */
+                    @Override
+                    public void onOutputBufferAvailable(MediaCodec codec, int index,
+                            MediaCodec.BufferInfo info) {
+                        lock.lock();
+                        try {
+                            // Stop dequeuing frames once a frame has been displayed
+                            if (displayedFrame.get()) {
+                                return;
+                            }
+                        } finally {
+                            lock.unlock();
+                        }
+                        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                            return;
+                        }
+                        codec.releaseOutputBuffer(index, true);
+                    }
+
+                    /**
+                     * Check if the error is transient. If it is, ignore it, otherwise signal end of
+                     * processing.
+                     */
+                    @Override
+                    public void onError(MediaCodec codec, MediaCodec.CodecException e) {
+                        if (e.isTransient()) {
+                            return;
+                        }
+                        lock.lock();
+                        try {
+                            processingDone.signal();
+                        } finally {
+                            lock.unlock();
+                        }
+                    }
+
+                    /** Ignore format changed events. */
+                    @Override
+                    public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) { }
+                };
+            final var onFrameRenderedListener = new MediaCodec.OnFrameRenderedListener() {
+                    @Override
+                    public void onFrameRendered(MediaCodec codec, long presentationTimeUs,
+                            long nanoTime) {
+                        lock.lock();
+                        try {
+                            displayedFrame.set(true);
+                            processingDone.signal();
+                        } finally {
+                            lock.unlock();
+                        }
+                    }
+                };
+            decoder.setCallback(cb);
+            decoder.setOnFrameRenderedListener(onFrameRenderedListener, null /* handler */);
+            scenario.onActivity(activity -> activity.hideSystemBars());
+            decoder.configure(format, surface.get(), null /* MediaCrypto */, 0 /* flags */);
+            // Start playback
+            decoder.start();
+            final long startTime = System.currentTimeMillis();
+            // Wait until the codec has decoded a frame, or a timeout.
+            lock.lock();
+            try {
+                long startTimeMs = System.currentTimeMillis();
+                long timeoutMs = 1000;
+                while ((System.currentTimeMillis() < startTimeMs + timeoutMs) &&
+                        !displayedFrame.get()) {
+                    processingDone.await(timeoutMs, TimeUnit.MILLISECONDS);
+                }
+            } finally {
+                lock.unlock();
+            }
+            Assert.assertTrue("Could not render any frame.", displayedFrame.get());
+            final ScreenCapture captureBeforeStop = Screenshot.capture();
+            Assert.assertFalse("Frame is blank before stop.", isUniformlyBlank(
+                            captureBeforeStop.getBitmap()));
+            decoder.stop();
+            final ScreenCapture captureAfterStop = Screenshot.capture();
+            Assert.assertTrue("Frame is not blank after stop.", isUniformlyBlank(
+                            captureAfterStop.getBitmap()));
+            decoder.release();
+            extractor.release();
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
+    @Test
+    public void testPushBlankBuffersOnStopVp9() throws Exception {
+        testPushBlankBuffersOnStop(
+                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
+    @Test
+    public void testPushBlankBuffersOnStopAvc() throws Exception {
+        testPushBlankBuffersOnStop(
+                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+    }
+}
diff --git a/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java b/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java
index 7f38ea4..4afc7aa 100644
--- a/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java
+++ b/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java
@@ -65,6 +65,7 @@
 import org.junit.runners.Parameterized;
 
 import java.io.IOException;
+import java.lang.Throwable;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -177,21 +178,36 @@
                 }
                 public void onInputBufferAvailable(MediaCodec codec, int ix) {
                     if (it.hasNext()) {
-                        Pair<ByteBuffer, BufferInfo> el = it.next();
-                        el.first.clear();
                         try {
-                            codec.getInputBuffer(ix).put(el.first);
-                        } catch (java.nio.BufferOverflowException e) {
-                            Log.e(TAG, "cannot fit " + el.first.limit()
-                                    + "-byte encoded buffer into "
-                                    + codec.getInputBuffer(ix).remaining()
-                                    + "-byte input buffer of " + codec.getName()
-                                    + " configured for " + codec.getInputFormat());
-                            throw e;
+                            Pair<ByteBuffer, BufferInfo> el = it.next();
+                            el.first.clear();
+                            try {
+                                codec.getInputBuffer(ix).put(el.first);
+                            } catch (java.nio.BufferOverflowException e) {
+                                String diagnostic = "cannot fit " + el.first.limit()
+                                        + "-byte encoded buffer into "
+                                        + codec.getInputBuffer(ix).remaining()
+                                        + "-byte input buffer of " + codec.getName()
+                                        + " configured for " + codec.getInputFormat();
+                                Log.e(TAG, diagnostic);
+                                errorMsg.set(diagnostic + e);
+                                synchronized (condition) {
+                                    condition.notifyAll();
+                                }
+                                // no sense trying to enqueue the failed buffer
+                                return;
+                            }
+                            BufferInfo info = el.second;
+                                codec.queueInputBuffer(
+                                    ix, 0, info.size, info.presentationTimeUs, info.flags);
+                        } catch (Throwable t) {
+                          errorMsg.set("exception in onInputBufferAvailable( "
+                                       +  codec.getName() + "," + ix
+                                       + "): " + t);
+                          synchronized (condition) {
+                              condition.notifyAll();
+                          }
                         }
-                        BufferInfo info = el.second;
-                        codec.queueInputBuffer(
-                                ix, 0, info.size, info.presentationTimeUs, info.flags);
                     }
                 }
                 public void onError(MediaCodec codec, MediaCodec.CodecException e) {
diff --git a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
index 75275d6..67c6003 100644
--- a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
@@ -19,11 +19,9 @@
 import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
 import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
@@ -40,9 +38,9 @@
 import android.os.vibrator.VibratorFrequencyProfile;
 import android.util.SparseArray;
 
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.AdoptShellPermissionsRule;
@@ -61,8 +59,8 @@
 @RunWith(AndroidJUnit4.class)
 public class VibratorManagerTest {
     @Rule
-    public ActivityTestRule<SimpleTestActivity> mActivityRule = new ActivityTestRule<>(
-            SimpleTestActivity.class);
+    public ActivityScenarioRule<SimpleTestActivity> mActivityRule =
+            new ActivityScenarioRule<>(SimpleTestActivity.class);
 
     @Rule
     public final AdoptShellPermissionsRule mAdoptShellPermissionsRule =
@@ -75,10 +73,6 @@
 
     private static final float TEST_TOLERANCE = 1e-5f;
 
-    private static final float MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY = 1f;
-    private static final float MINIMUM_ACCEPTED_FREQUENCY = 1f;
-    private static final float MAXIMUM_ACCEPTED_FREQUENCY = 1_000f;
-
     private static final long CALLBACK_TIMEOUT_MILLIS = 5_000;
     private static final VibrationAttributes VIBRATION_ATTRIBUTES =
             new VibrationAttributes.Builder()
@@ -134,6 +128,32 @@
     }
 
     @Test
+    public void testGetVibratorIds() {
+        // Just make sure it doesn't crash or return null when this is called; we don't really have
+        // a way to test which vibrators will be returned.
+        assertThat(mVibratorManager.getVibratorIds()).isNotNull();
+        assertThat(mVibratorManager.getVibratorIds()).asList().containsNoDuplicates();
+    }
+
+    @Test
+    public void testGetNonExistentVibratorId() {
+        int missingId = Arrays.stream(mVibratorManager.getVibratorIds()).max().orElse(0) + 1;
+        Vibrator vibrator = mVibratorManager.getVibrator(missingId);
+        assertThat(vibrator).isNotNull();
+        assertThat(vibrator.hasVibrator()).isFalse();
+    }
+
+    @Test
+    public void testGetDefaultVibratorIsSameAsVibratorService() {
+        // Note that VibratorTest parameterization relies on these two vibrators being identical.
+        // It only runs vibrator tests on the result of one of the APIs.
+        Vibrator systemVibrator =
+                InstrumentationRegistry.getInstrumentation().getContext().getSystemService(
+                        Vibrator.class);
+        assertThat(mVibratorManager.getDefaultVibrator()).isSameInstanceAs(systemVibrator);
+    }
+
+    @Test
     public void testCancel() {
         mVibratorManager.vibrate(CombinedVibration.createParallel(
                 VibrationEffect.createOneShot(10_000, VibrationEffect.DEFAULT_AMPLITUDE)));
@@ -145,7 +165,7 @@
 
     @LargeTest
     @Test
-    public void testVibrateOneShotStartsAndFinishesVibration() {
+    public void testCombinedVibrationOneShotStartsAndFinishesVibration() {
         VibrationEffect oneShot =
                 VibrationEffect.createOneShot(300, VibrationEffect.DEFAULT_AMPLITUDE);
         mVibratorManager.vibrate(CombinedVibration.createParallel(oneShot));
@@ -153,7 +173,7 @@
     }
 
     @Test
-    public void testVibrateOneShotMaxAmplitude() {
+    public void testCombinedVibrationOneShotMaxAmplitude() {
         VibrationEffect oneShot = VibrationEffect.createOneShot(500, 255 /* Max amplitude */);
         mVibratorManager.vibrate(CombinedVibration.createParallel(oneShot));
         assertStartsVibrating();
@@ -163,7 +183,7 @@
     }
 
     @Test
-    public void testVibrateOneShotMinAmplitude() {
+    public void testCombinedVibrationOneShotMinAmplitude() {
         VibrationEffect oneShot = VibrationEffect.createOneShot(100, 1 /* Min amplitude */);
         mVibratorManager.vibrate(CombinedVibration.createParallel(oneShot),
                 VIBRATION_ATTRIBUTES);
@@ -172,7 +192,7 @@
 
     @LargeTest
     @Test
-    public void testVibrateWaveformStartsAndFinishesVibration() {
+    public void testCombinedVibrationWaveformStartsAndFinishesVibration() {
         final long[] timings = new long[]{100, 200, 300, 400, 500};
         final int[] amplitudes = new int[]{64, 128, 255, 128, 64};
         VibrationEffect waveform = VibrationEffect.createWaveform(timings, amplitudes, -1);
@@ -182,7 +202,7 @@
 
     @LargeTest
     @Test
-    public void testVibrateWaveformRepeats() {
+    public void testCombinedVibrationWaveformRepeats() {
         final long[] timings = new long[]{100, 200, 300, 400, 500};
         final int[] amplitudes = new int[]{64, 128, 255, 128, 64};
         VibrationEffect waveform = VibrationEffect.createWaveform(timings, amplitudes, 0);
@@ -192,68 +212,60 @@
         SystemClock.sleep(2000);
         int[] vibratorIds = mVibratorManager.getVibratorIds();
         for (int vibratorId : vibratorIds) {
-            assertTrue(mVibratorManager.getVibrator(vibratorId).isVibrating());
+            assertThat(mVibratorManager.getVibrator(vibratorId).isVibrating()).isTrue();
         }
 
         mVibratorManager.cancel();
         assertStopsVibrating();
     }
 
-
     @LargeTest
     @Test
-    public void testVibrateWaveformWithFrequencyStartsAndFinishesVibration() {
-        int[] vibratorIds = mVibratorManager.getVibratorIds();
-        for (int vibratorId : vibratorIds) {
-            Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
-            if (!vibrator.hasFrequencyControl()) {
-                continue;
-            }
-            VibratorFrequencyProfile frequencyProfile = vibrator.getFrequencyProfile();
+    public void testCombinedVibrationWaveformWithFrequencyStartsAndFinishesVibration() {
+        Vibrator defaultVibrator = mVibratorManager.getDefaultVibrator();
+        assumeTrue(defaultVibrator.hasFrequencyControl());
 
-            float minFrequency = frequencyProfile.getMinFrequency();
-            float maxFrequency = frequencyProfile.getMaxFrequency();
-            float resonantFrequency = vibrator.getResonantFrequency();
-            float sustainFrequency = Float.isNaN(resonantFrequency)
-                    ? (maxFrequency + minFrequency) / 2
-                    : resonantFrequency;
+        VibratorFrequencyProfile frequencyProfile = defaultVibrator.getFrequencyProfile();
+        float minFrequency = frequencyProfile.getMinFrequency();
+        float maxFrequency = frequencyProfile.getMaxFrequency();
+        float resonantFrequency = defaultVibrator.getResonantFrequency();
+        float sustainFrequency = Float.isNaN(resonantFrequency)
+                ? (maxFrequency + minFrequency) / 2
+                : resonantFrequency;
 
-            // Then ramp to zero amplitude at fixed frequency.
-            VibrationEffect waveform =
-                    VibrationEffect.startWaveform(targetAmplitude(0), targetFrequency(minFrequency))
-                            // Ramp from min to max frequency and from zero to max amplitude.
-                            .addTransition(Duration.ofMillis(10),
-                                    targetAmplitude(1), targetFrequency(maxFrequency))
-                            // Ramp back to min frequency and zero amplitude.
-                            .addTransition(Duration.ofMillis(10),
-                                    targetAmplitude(0), targetFrequency(minFrequency))
-                            // Then sustain at a fixed frequency and half amplitude.
-                            .addTransition(Duration.ZERO,
-                                    targetAmplitude(0.5f), targetFrequency(sustainFrequency))
-                            .addSustain(Duration.ofMillis(20))
-                            // Ramp from min to max frequency and at max amplitude.
-                            .addTransition(Duration.ZERO,
-                                    targetAmplitude(1), targetFrequency(minFrequency))
-                            .addTransition(Duration.ofMillis(10), targetFrequency(maxFrequency))
-                            // Ramp from max to min amplitude at max frequency.
-                            .addTransition(Duration.ofMillis(10), targetAmplitude(0))
-                            .build();
-            vibrator.vibrate(waveform);
-            assertStartsVibrating(vibratorId);
-            assertStopsVibrating();
-        }
+        // Then ramp to zero amplitude at fixed frequency.
+        VibrationEffect waveform =
+                VibrationEffect.startWaveform(targetAmplitude(0), targetFrequency(minFrequency))
+                        // Ramp from min to max frequency and from zero to max amplitude.
+                        .addTransition(Duration.ofMillis(10),
+                                targetAmplitude(1), targetFrequency(maxFrequency))
+                        // Ramp back to min frequency and zero amplitude.
+                        .addTransition(Duration.ofMillis(10),
+                                targetAmplitude(0), targetFrequency(minFrequency))
+                        // Then sustain at a fixed frequency and half amplitude.
+                        .addTransition(Duration.ZERO,
+                                targetAmplitude(0.5f), targetFrequency(sustainFrequency))
+                        .addSustain(Duration.ofMillis(20))
+                        // Ramp from min to max frequency and at max amplitude.
+                        .addTransition(Duration.ZERO,
+                                targetAmplitude(1), targetFrequency(minFrequency))
+                        .addTransition(Duration.ofMillis(10), targetFrequency(maxFrequency))
+                        // Ramp from max to min amplitude at max frequency.
+                        .addTransition(Duration.ofMillis(10), targetAmplitude(0))
+                        .build();
+        mVibratorManager.vibrate(CombinedVibration.createParallel(waveform));
+        assertStartsThenStopsVibrating(50);
     }
 
     @Test
-    public void testVibrateSingleVibrator() {
+    public void testCombinedVibrationTargetingSingleVibrator() {
         int[] vibratorIds = mVibratorManager.getVibratorIds();
-        if (vibratorIds.length < 2) {
-            return;
-        }
+        assumeTrue(vibratorIds.length >= 2);
 
         VibrationEffect oneShot =
                 VibrationEffect.createOneShot(10_000, VibrationEffect.DEFAULT_AMPLITUDE);
 
+        // Vibrate each vibrator in turn, and assert that all the others are off.
         for (int vibratorId : vibratorIds) {
             Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
             mVibratorManager.vibrate(
@@ -264,7 +276,8 @@
 
             for (int otherVibratorId : vibratorIds) {
                 if (otherVibratorId != vibratorId) {
-                    assertFalse(mVibratorManager.getVibrator(otherVibratorId).isVibrating());
+                    assertThat(mVibratorManager.getVibrator(otherVibratorId).isVibrating())
+                            .isFalse();
                 }
             }
 
@@ -273,130 +286,6 @@
         }
     }
 
-    @Test
-    public void testGetVibratorIds() {
-        // Just make sure it doesn't crash or return null when this is called; we don't really have
-        // a way to test which vibrators will be returned.
-        assertNotNull(mVibratorManager.getVibratorIds());
-    }
-
-    @Test
-    public void testGetNonExistentVibratorId() {
-        int missingId = Arrays.stream(mVibratorManager.getVibratorIds()).max().orElse(0) + 1;
-        Vibrator vibrator = mVibratorManager.getVibrator(missingId);
-        assertNotNull(vibrator);
-        assertFalse(vibrator.hasVibrator());
-    }
-
-    @Test
-    public void testGetDefaultVibrator() {
-        Vibrator systemVibrator =
-                InstrumentationRegistry.getInstrumentation().getContext().getSystemService(
-                        Vibrator.class);
-        assertSame(systemVibrator, mVibratorManager.getDefaultVibrator());
-    }
-
-    @Test
-    public void testSingleVibratorIsPresent() {
-        for (int vibratorId : mVibratorManager.getVibratorIds()) {
-            Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
-            assertNotNull(vibrator);
-            assertEquals(vibratorId, vibrator.getId());
-            assertTrue(vibrator.hasVibrator());
-        }
-    }
-
-    @Test
-    public void testSingleVibratorAmplitudeAndFrequencyControls() {
-        for (int vibratorId : mVibratorManager.getVibratorIds()) {
-            Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
-            assertNotNull(vibrator);
-
-            // Just check this method will not crash.
-            vibrator.hasAmplitudeControl();
-
-            // Single vibrators should return the frequency profile when it has frequency control.
-            assertEquals(vibrator.hasFrequencyControl(),
-                    vibrator.getFrequencyProfile() != null);
-        }
-    }
-
-    @Test
-    public void testSingleVibratorFrequencyProfile() {
-        for (int vibratorId : mVibratorManager.getVibratorIds()) {
-            Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
-            VibratorFrequencyProfile frequencyProfile = vibrator.getFrequencyProfile();
-            if (frequencyProfile == null) {
-                continue;
-            }
-
-            float measurementIntervalHz = frequencyProfile.getMaxAmplitudeMeasurementInterval();
-            assertTrue(measurementIntervalHz >= MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY);
-
-            float resonantFrequency = vibrator.getResonantFrequency();
-            float minFrequencyHz = frequencyProfile.getMinFrequency();
-            float maxFrequencyHz = frequencyProfile.getMaxFrequency();
-
-            assertTrue(minFrequencyHz >= MINIMUM_ACCEPTED_FREQUENCY);
-            assertTrue(maxFrequencyHz > minFrequencyHz);
-            assertTrue(maxFrequencyHz <= MAXIMUM_ACCEPTED_FREQUENCY);
-
-            if (!Float.isNaN(resonantFrequency)) {
-                // If the device has a resonant frequency, then it should be within the supported
-                // frequency range described by the profile.
-                assertTrue(resonantFrequency >= minFrequencyHz);
-                assertTrue(resonantFrequency <= maxFrequencyHz);
-            }
-
-            float[] measurements = frequencyProfile.getMaxAmplitudeMeasurements();
-
-            // There should be at least 3 points for a valid profile.
-            assertTrue(measurements.length > 2);
-            assertEquals(maxFrequencyHz,
-                    minFrequencyHz + ((measurements.length - 1) * measurementIntervalHz),
-                    TEST_TOLERANCE);
-
-            boolean hasPositiveMeasurement = false;
-            for (float measurement : measurements) {
-                assertTrue(measurement >= 0);
-                assertTrue(measurement <= 1);
-                hasPositiveMeasurement |= measurement > 0;
-            }
-            assertTrue(hasPositiveMeasurement);
-        }
-    }
-
-    @Test
-    public void testSingleVibratorEffectAndPrimitiveSupport() {
-        for (int vibratorId : mVibratorManager.getVibratorIds()) {
-            Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
-            assertNotNull(vibrator);
-
-            // Just check these methods return valid support arrays.
-            // We don't really have a way to test if the device supports each effect or not.
-            assertEquals(2, vibrator.areEffectsSupported(
-                    VibrationEffect.EFFECT_TICK, VibrationEffect.EFFECT_CLICK).length);
-            assertEquals(2, vibrator.arePrimitivesSupported(
-                    VibrationEffect.Composition.PRIMITIVE_CLICK,
-                    VibrationEffect.Composition.PRIMITIVE_TICK).length);
-        }
-    }
-
-    @Test
-    public void testSingleVibratorVibrateAndCancel() {
-        for (int vibratorId : mVibratorManager.getVibratorIds()) {
-            Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
-            assertNotNull(vibrator);
-
-            vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
-            assertStartsVibrating(vibratorId);
-            assertTrue(vibrator.isVibrating());
-
-            vibrator.cancel();
-            assertStopsVibrating(vibratorId);
-        }
-    }
-
     private void assertStartsThenStopsVibrating(long duration) {
         for (int i = 0; i < mStateListeners.size(); i++) {
             assertVibratorState(mStateListeners.keyAt(i), true);
diff --git a/tests/tests/os/src/android/os/cts/VibratorTest.java b/tests/tests/os/src/android/os/cts/VibratorTest.java
index 7df216c..c026296 100644
--- a/tests/tests/os/src/android/os/cts/VibratorTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorTest.java
@@ -19,10 +19,11 @@
 import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
 import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeNotNull;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.eq;
@@ -39,20 +40,23 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.Vibrator.OnVibratorStateChangedListener;
+import android.os.VibratorManager;
 import android.os.vibrator.VibratorFrequencyProfile;
 
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.AdoptShellPermissionsRule;
 
+import com.google.common.collect.Range;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -62,11 +66,17 @@
 import java.util.List;
 import java.util.concurrent.Executors;
 
-@RunWith(AndroidJUnit4.class)
+/**
+ * Verifies the Vibrator API for all surfaces that present it, as enumerated by the {@link #data()}
+ * method.
+ */
+@RunWith(Parameterized.class)
 public class VibratorTest {
+    private static final String SYSTEM_VIBRATOR_LABEL = "SystemVibrator";
+
     @Rule
-    public ActivityTestRule<SimpleTestActivity> mActivityRule = new ActivityTestRule<>(
-            SimpleTestActivity.class);
+    public ActivityScenarioRule<SimpleTestActivity> mActivityRule =
+            new ActivityScenarioRule<>(SimpleTestActivity.class);
 
     @Rule
     public final AdoptShellPermissionsRule mAdoptShellPermissionsRule =
@@ -77,6 +87,43 @@
     @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
+    /**
+     *  Provides the vibrator accessed with the given vibrator ID, at the time of test running.
+     *  A vibratorId of -1 indicates to use the system default vibrator.
+     */
+    private interface VibratorProvider {
+        Vibrator getVibrator();
+    }
+
+    /** Helper to add test parameters more readably and without explicit casting. */
+    private static void addTestParameter(ArrayList<Object[]> data, String testLabel,
+            VibratorProvider vibratorProvider) {
+        data.add(new Object[] { testLabel, vibratorProvider });
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        // Test params are Name,Vibrator pairs. All vibrators on the system should conform to this
+        // test.
+        ArrayList<Object[]> data = new ArrayList<>();
+        // These vibrators should be identical, but verify both APIs explicitly.
+        addTestParameter(data, SYSTEM_VIBRATOR_LABEL,
+                () -> InstrumentationRegistry.getInstrumentation().getContext()
+                        .getSystemService(Vibrator.class));
+        // VibratorManager also presents getDefaultVibrator, but in VibratorManagerTest
+        // it is asserted that the Vibrator system service and getDefaultVibrator are
+        // the same object, so we don't test it twice here.
+
+        VibratorManager vibratorManager = InstrumentationRegistry.getInstrumentation().getContext()
+                .getSystemService(VibratorManager.class);
+        for (int vibratorId : vibratorManager.getVibratorIds()) {
+            addTestParameter(data, "vibratorId:" + vibratorId,
+                    () -> InstrumentationRegistry.getInstrumentation().getContext()
+                            .getSystemService(VibratorManager.class).getVibrator(vibratorId));
+        }
+        return data;
+    }
+
     private static final float TEST_TOLERANCE = 1e-5f;
 
     private static final float MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY = 1f;
@@ -125,6 +172,9 @@
             VibrationAttributes.USAGE_TOUCH,
     };
 
+    private final String mVibratorLabel;
+    private final Vibrator mVibrator;
+
     /**
      * This listener is used for test helper methods like asserting it starts/stops vibrating.
      * It's not strongly required that the interactions with this mock are validated by all tests.
@@ -132,15 +182,18 @@
     @Mock
     private OnVibratorStateChangedListener mStateListener;
 
-    private Vibrator mVibrator;
     /** Keep track of any listener created to be added to the vibrator, for cleanup purposes. */
     private List<OnVibratorStateChangedListener> mStateListenersCreated = new ArrayList<>();
 
+    // vibratorLabel is used by the parameterized test infrastructure.
+    public VibratorTest(String vibratorLabel, VibratorProvider vibratorProvider) {
+        mVibratorLabel = vibratorLabel;
+        mVibrator = vibratorProvider.getVibrator();
+        assertThat(mVibrator).isNotNull();
+    }
+
     @Before
     public void setUp() {
-        mVibrator = InstrumentationRegistry.getInstrumentation().getContext().getSystemService(
-                Vibrator.class);
-
         mVibrator.addVibratorStateListener(mStateListener);
         // Adding a listener to the Vibrator should trigger the callback once with the current
         // vibrator state, so reset mocks to clear it for tests.
@@ -168,17 +221,36 @@
     }
 
     @Test
+    public void testSystemVibratorGetIdAndMaybeHasVibrator() {
+        assumeTrue(isSystemVibrator());
+
+        // The system vibrator should not be mapped to any physical vibrator and use a default id.
+        assertThat(mVibrator.getId()).isEqualTo(-1);
+        // The system vibrator always exists, but may not actually have a vibrator. Just make sure
+        // the API doesn't throw.
+        mVibrator.hasVibrator();
+    }
+
+    @Test
+    public void testNonSystemVibratorGetIdAndAlwaysHasVibrator() {
+        assumeFalse(isSystemVibrator());
+        assertThat(mVibrator.hasVibrator()).isTrue();
+    }
+
+    @Test
     public void getDefaultVibrationIntensity_returnsValidIntensityForAllUsages() {
         for (int usage : VIBRATION_USAGES) {
             int intensity = mVibrator.getDefaultVibrationIntensity(usage);
-            assertTrue("Error for usage " + usage + " with default intensity " + intensity,
-                    (intensity >= Vibrator.VIBRATION_INTENSITY_OFF)
-                            && (intensity <= Vibrator.VIBRATION_INTENSITY_HIGH));
+            assertWithMessage("Default intensity invalid for usage " + usage)
+                    .that(intensity)
+                    .isIn(Range.closed(
+                            Vibrator.VIBRATION_INTENSITY_OFF, Vibrator.VIBRATION_INTENSITY_HIGH));
         }
 
-        assertEquals("Invalid usage expected to have same default as USAGE_UNKNOWN",
-                mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_UNKNOWN),
-                mVibrator.getDefaultVibrationIntensity(-1));
+        assertWithMessage("Invalid usage expected to have same default as USAGE_UNKNOWN")
+                .that(mVibrator.getDefaultVibrationIntensity(-1))
+                .isEqualTo(
+                    mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_UNKNOWN));
     }
 
     @Test
@@ -196,31 +268,23 @@
         mVibrator.vibrate(pattern, 3);
         assertStartsVibrating();
 
-        try {
-            mVibrator.vibrate(pattern, 10);
-            fail("Should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException expected) {
-        }
+        // Repeat index is invalid.
+        assertThrows(ArrayIndexOutOfBoundsException.class, () -> mVibrator.vibrate(pattern, 10));
     }
 
     @Test
-    public void testVibrateMultiThread() {
-        new Thread(() -> {
-            try {
-                mVibrator.vibrate(500);
-            } catch (Exception e) {
-                fail("MultiThread fail1");
-            }
+    public void testVibrateMultiThread() throws Exception {
+        ThreadHelper thread1 = new ThreadHelper(() -> {
+            mVibrator.vibrate(200);
         }).start();
-        new Thread(() -> {
-            try {
-                // This test only get two threads to run vibrator at the same time for a functional
-                // test, but it can not verify if the second thread get the precedence.
-                mVibrator.vibrate(1000);
-            } catch (Exception e) {
-                fail("MultiThread fail2");
-            }
+        ThreadHelper thread2 = new ThreadHelper(() -> {
+            // This test only get two threads to run vibrator at the same time for a functional
+            // test, but can't assert ordering.
+            mVibrator.vibrate(100);
         }).start();
+        thread1.joinSafely();
+        thread2.joinSafely();
+
         assertStartsVibrating();
     }
 
@@ -270,7 +334,7 @@
         assertStartsVibrating();
 
         SystemClock.sleep(2000);
-        assertTrue(!mVibrator.hasVibrator() || mVibrator.isVibrating());
+        assertIsVibrating(true);
 
         mVibrator.cancel();
         assertStopsVibrating();
@@ -283,13 +347,18 @@
         VibratorFrequencyProfile frequencyProfile = mVibrator.getFrequencyProfile();
         assumeNotNull(frequencyProfile);
 
-        float minFrequency = Math.max(1f, frequencyProfile.getMinFrequency());
+        float minFrequency = frequencyProfile.getMinFrequency();
         float maxFrequency = frequencyProfile.getMaxFrequency();
         float resonantFrequency = mVibrator.getResonantFrequency();
         float sustainFrequency = Float.isNaN(resonantFrequency)
-                ? (maxFrequency - minFrequency) / 2
+                ? (maxFrequency + minFrequency) / 2
                 : resonantFrequency;
 
+        // Ensure the values can be used as a targetFrequency.
+        assertThat(minFrequency).isAtLeast(MINIMUM_ACCEPTED_FREQUENCY);
+        assertThat(maxFrequency).isAtLeast(minFrequency);
+        assertThat(maxFrequency).isAtMost(MAXIMUM_ACCEPTED_FREQUENCY);
+
         // Ramp from min to max frequency and from zero to max amplitude.
         // Then ramp to a fixed frequency at max amplitude.
         // Then ramp to zero amplitude at fixed frequency.
@@ -349,19 +418,6 @@
     }
 
     @Test
-    public void testGetId() {
-        // The system vibrator should not be mapped to any physical vibrator and use a default id.
-        assertEquals(-1, mVibrator.getId());
-    }
-
-    @Test
-    public void testHasVibrator() {
-        // Just make sure it doesn't crash when this is called; we don't really have a way to test
-        // if the device has vibrator or not.
-        mVibrator.hasVibrator();
-    }
-
-    @Test
     public void testVibratorHasAmplitudeControl() {
         // Just make sure it doesn't crash when this is called; we don't really have a way to test
         // if the amplitude control works or not.
@@ -372,16 +428,25 @@
     public void testVibratorHasFrequencyControl() {
         // Just make sure it doesn't crash when this is called; we don't really have a way to test
         // if the frequency control works or not.
-        mVibrator.hasFrequencyControl();
+        if (mVibrator.hasFrequencyControl()) {
+            // If it's a multi-vibrator device, the system vibrator presents a merged frequency
+            // profile, which may in turn be empty, and hence null. But otherwise, it should not
+            // be null.
+            if (!isMultiVibratorDevice() || !isSystemVibrator()) {
+                assertThat(mVibrator.getFrequencyProfile()).isNotNull();
+            }
+        } else {
+            assertThat(mVibrator.getFrequencyProfile()).isNull();
+        }
     }
 
     @Test
     public void testVibratorEffectsAreSupported() {
         // Just make sure it doesn't crash when this is called and that it returns all queries;
         // We don't really have a way to test if the device supports each effect or not.
-        assertEquals(PREDEFINED_EFFECTS.length,
-                mVibrator.areEffectsSupported(PREDEFINED_EFFECTS).length);
-        assertEquals(0, mVibrator.areEffectsSupported().length);
+        assertThat(mVibrator.areEffectsSupported(PREDEFINED_EFFECTS))
+                .hasLength(PREDEFINED_EFFECTS.length);
+        assertThat(mVibrator.areEffectsSupported()).isEmpty();
     }
 
     @Test
@@ -389,16 +454,17 @@
         // Just make sure it doesn't crash when this is called;
         // We don't really have a way to test if the device supports each effect or not.
         mVibrator.areAllEffectsSupported(PREDEFINED_EFFECTS);
-        assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES, mVibrator.areAllEffectsSupported());
+        assertThat(mVibrator.areAllEffectsSupported())
+                .isEqualTo(Vibrator.VIBRATION_EFFECT_SUPPORT_YES);
     }
 
     @Test
     public void testVibratorPrimitivesAreSupported() {
         // Just make sure it doesn't crash when this is called;
         // We don't really have a way to test if the device supports each effect or not.
-        assertEquals(PRIMITIVE_EFFECTS.length,
-                mVibrator.arePrimitivesSupported(PRIMITIVE_EFFECTS).length);
-        assertEquals(0, mVibrator.arePrimitivesSupported().length);
+        assertThat(mVibrator.arePrimitivesSupported(PRIMITIVE_EFFECTS)).hasLength(
+                PRIMITIVE_EFFECTS.length);
+        assertThat(mVibrator.arePrimitivesSupported()).isEmpty();
     }
 
     @Test
@@ -406,29 +472,36 @@
         // Just make sure it doesn't crash when this is called;
         // We don't really have a way to test if the device supports each effect or not.
         mVibrator.areAllPrimitivesSupported(PRIMITIVE_EFFECTS);
-        assertTrue(mVibrator.areAllPrimitivesSupported());
+        assertThat(mVibrator.areAllPrimitivesSupported()).isTrue();
     }
 
     @Test
     public void testVibratorPrimitivesDurations() {
         int[] durations = mVibrator.getPrimitiveDurations(PRIMITIVE_EFFECTS);
         boolean[] supported = mVibrator.arePrimitivesSupported(PRIMITIVE_EFFECTS);
-        assertEquals(PRIMITIVE_EFFECTS.length, durations.length);
+        assertThat(durations).hasLength(PRIMITIVE_EFFECTS.length);
         for (int i = 0; i < durations.length; i++) {
-            assertEquals("Primitive " + PRIMITIVE_EFFECTS[i]
-                            + " expected to have " + (supported[i] ? "positive" : "zero")
-                            + " duration, found " + durations[i] + "ms",
-                    supported[i], durations[i] > 0);
+            if (supported[i]) {
+                assertWithMessage("Supported primitive " + PRIMITIVE_EFFECTS[i]
+                        + " should have positive duration")
+                        .that(durations[i]).isGreaterThan(0);
+            } else {
+                assertWithMessage("Unsupported primitive " + PRIMITIVE_EFFECTS[i]
+                        + " should have zero duration")
+                        .that(durations[i]).isEqualTo(0);
+
+            }
         }
-        assertEquals(0, mVibrator.getPrimitiveDurations().length);
+        assertThat(mVibrator.getPrimitiveDurations()).isEmpty();
     }
 
     @Test
     public void testVibratorResonantFrequency() {
         // Check that the resonant frequency provided is NaN, or if it's a reasonable value.
         float resonantFrequency = mVibrator.getResonantFrequency();
-        assertTrue(Float.isNaN(resonantFrequency)
-                || (resonantFrequency > 0 && resonantFrequency < MAXIMUM_ACCEPTED_FREQUENCY));
+        if (!Float.isNaN(resonantFrequency)) {
+            assertThat(resonantFrequency).isIn(Range.open(0f, MAXIMUM_ACCEPTED_FREQUENCY));
+        }
     }
 
     @Test
@@ -444,7 +517,7 @@
 
         // If the frequency profile is present then the vibrator must have frequency control.
         // The other implication is not true if the default vibrator represents multiple vibrators.
-        assertTrue(mVibrator.hasFrequencyControl());
+        assertThat(mVibrator.hasFrequencyControl()).isTrue();
     }
 
     @Test
@@ -453,7 +526,8 @@
         assumeNotNull(frequencyProfile);
 
         float measurementIntervalHz = frequencyProfile.getMaxAmplitudeMeasurementInterval();
-        assertTrue(measurementIntervalHz >= MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY);
+        assertThat(measurementIntervalHz)
+                .isAtLeast(MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY);
     }
 
     @Test
@@ -465,15 +539,15 @@
         float minFrequencyHz = frequencyProfile.getMinFrequency();
         float maxFrequencyHz = frequencyProfile.getMaxFrequency();
 
-        assertTrue(minFrequencyHz >= MINIMUM_ACCEPTED_FREQUENCY);
-        assertTrue(maxFrequencyHz > minFrequencyHz);
-        assertTrue(maxFrequencyHz <= MAXIMUM_ACCEPTED_FREQUENCY);
+        assertThat(minFrequencyHz).isAtLeast(MINIMUM_ACCEPTED_FREQUENCY);
+        assertThat(maxFrequencyHz).isGreaterThan(minFrequencyHz);
+        assertThat(maxFrequencyHz).isAtMost(MAXIMUM_ACCEPTED_FREQUENCY);
 
         if (!Float.isNaN(resonantFrequency)) {
             // If the device has a resonant frequency, then it should be within the supported
             // frequency range described by the profile.
-            assertTrue(resonantFrequency >= minFrequencyHz);
-            assertTrue(resonantFrequency <= maxFrequencyHz);
+            assertThat(resonantFrequency).isAtLeast(minFrequencyHz);
+            assertThat(resonantFrequency).isAtMost(maxFrequencyHz);
         }
     }
 
@@ -488,33 +562,31 @@
         float[] measurements = frequencyProfile.getMaxAmplitudeMeasurements();
 
         // There should be at least 3 points for a valid profile: min, center and max frequencies.
-        assertTrue(measurements.length > 2);
-        assertEquals(maxFrequencyHz,
-                minFrequencyHz + ((measurements.length - 1) * measurementIntervalHz),
-                TEST_TOLERANCE);
+        assertThat(measurements.length).isAtLeast(3);
+        assertThat(minFrequencyHz + ((measurements.length - 1) * measurementIntervalHz))
+                .isWithin(TEST_TOLERANCE).of(maxFrequencyHz);
 
         boolean hasPositiveMeasurement = false;
         for (float measurement : measurements) {
-            assertTrue(measurement >= 0);
-            assertTrue(measurement <= 1);
+            assertThat(measurement).isIn(Range.closed(0f, 1f));
             hasPositiveMeasurement |= measurement > 0;
         }
-        assertTrue(hasPositiveMeasurement);
+        assertThat(hasPositiveMeasurement).isTrue();
     }
 
     @Test
     public void testVibratorIsVibrating() {
         assumeTrue(mVibrator.hasVibrator());
 
-        assertFalse(mVibrator.isVibrating());
+        assertThat(mVibrator.isVibrating()).isFalse();
 
         mVibrator.vibrate(5000);
         assertStartsVibrating();
-        assertTrue(mVibrator.isVibrating());
+        assertThat(mVibrator.isVibrating()).isTrue();
 
         mVibrator.cancel();
         assertStopsVibrating();
-        assertFalse(mVibrator.isVibrating());
+        assertThat(mVibrator.isVibrating()).isFalse();
     }
 
     @LargeTest
@@ -526,7 +598,7 @@
         assertStartsVibrating();
 
         SystemClock.sleep(1500);
-        assertFalse(mVibrator.isVibrating());
+        assertThat(mVibrator.isVibrating()).isFalse();
     }
 
     @LargeTest
@@ -580,6 +652,15 @@
         verify(listener2, never()).onVibratorStateChanged(true);
     }
 
+    private boolean isSystemVibrator() {
+        return mVibratorLabel.equals(SYSTEM_VIBRATOR_LABEL);
+    }
+
+    private boolean isMultiVibratorDevice() {
+        return InstrumentationRegistry.getInstrumentation().getContext()
+                .getSystemService(VibratorManager.class).getVibratorIds().length > 1;
+    }
+
     private OnVibratorStateChangedListener newMockStateListener() {
         OnVibratorStateChangedListener listener = mock(OnVibratorStateChangedListener.class);
         mStateListenersCreated.add(listener);
@@ -594,6 +675,12 @@
         }
     }
 
+    private void assertIsVibrating(boolean expectedIsVibrating) {
+        if (mVibrator.hasVibrator()) {
+            assertThat(mVibrator.isVibrating()).isEqualTo(expectedIsVibrating);
+        }
+    }
+
     private void assertStartsVibrating() {
         assertVibratorState(true);
     }
@@ -608,4 +695,54 @@
                     .onVibratorStateChanged(eq(expected));
         }
     }
+
+    /**
+     * Supervises a thread execution with a custom uncaught exception handler.
+     *
+     * <p>{@link #joinSafely()} should be called for all threads to ensure that the thread didn't
+     * have an uncaught exception. Without this custom handler, the default uncaught handler kills
+     * the whole test instrumentation, causing all tests to appear failed, making debugging harder.
+     */
+    private class ThreadHelper implements Thread.UncaughtExceptionHandler {
+        private final Thread mThread;
+        private boolean mStarted;
+        private volatile Throwable mUncaughtException;
+
+        /**
+         * Creates the thread with the {@link Runnable}. {@link #start()} should still be called
+         * after this.
+         */
+        ThreadHelper(Runnable runnable) {
+            mThread = new Thread(runnable);
+            mThread.setUncaughtExceptionHandler(this);
+        }
+
+        /** Start the thread. This is mainly so the helper usage looks more thread-like. */
+        ThreadHelper start() {
+            assertThat(mStarted).isFalse();
+            mThread.start();
+            mStarted = true;
+            return this;
+        }
+
+        /** Join the thread and assert that there was no uncaught exception in it. */
+        void joinSafely() throws InterruptedException {
+            assertThat(mStarted).isTrue();
+            mThread.join();
+            assertThat(mUncaughtException).isNull();
+        }
+
+        @Override
+        public void uncaughtException(Thread t, Throwable e) {
+            // The default android handler kills the whole test instrumentation, which is
+            // why this class implements a softer version.
+            if (t != mThread || mUncaughtException != null) {
+                // The thread should always match, but we propagate if it doesn't somehow.
+                // We can't throw an exception here directly, as it would be ignored.
+                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, e);
+            } else {
+                mUncaughtException = e;
+            }
+        }
+    }
 }
diff --git a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
index 7555a6f..b29e99f 100644
--- a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
@@ -64,14 +64,10 @@
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
 class NotificationPermissionTest : BaseUsePermissionTest() {
 
-    // b/220968160: Notification permission is not enabled on TV devices.
-    @Before
-    fun assumeNotTv() = assumeFalse(isTv)
-
     private val cr = callWithShellPermissionIdentity {
         context.createContextAsUser(UserHandle.SYSTEM, 0).contentResolver
     }
-    private var previousEnableState = 0
+    private var previousEnableState = -1
     private var countDown: CountDownLatch = CountDownLatch(1)
     private var allowedGroups = listOf<String>()
     private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
@@ -84,6 +80,8 @@
 
     @Before
     fun setLatchAndEnablePermission() {
+        // b/220968160: Notification permission is not enabled on TV devices.
+        assumeFalse(isTv)
         runWithShellPermissionIdentity {
             previousEnableState = Settings.Secure.getInt(cr, NOTIFICATION_PERMISSION_ENABLED, 0)
             Settings.Secure.putInt(cr, NOTIFICATION_PERMISSION_ENABLED, 1)
@@ -95,10 +93,12 @@
 
     @After
     fun resetPermissionAndRemoveReceiver() {
-        runWithShellPermissionIdentity {
-            Settings.Secure.putInt(cr, NOTIFICATION_PERMISSION_ENABLED, previousEnableState)
+        if (previousEnableState >= 0) {
+            runWithShellPermissionIdentity {
+                Settings.Secure.putInt(cr, NOTIFICATION_PERMISSION_ENABLED, previousEnableState)
+            }
+            context.unregisterReceiver(receiver)
         }
-        context.unregisterReceiver(receiver)
     }
 
     @Test
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionAllServicesTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionAllServicesTest.kt
index d882b51..a0220be 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionAllServicesTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionAllServicesTest.kt
@@ -22,8 +22,10 @@
 import android.content.Intent
 import android.location.LocationManager
 import android.net.Uri
+import android.os.Build
 import android.provider.Settings
 import android.support.test.uiautomator.By
+import androidx.test.filters.SdkSuppress
 import com.android.compatibility.common.util.AppOpsUtils.setOpMode
 import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
 import com.android.compatibility.common.util.SystemUtil.eventually
@@ -37,6 +39,7 @@
 import org.junit.Test
 
 @CtsDownstreamingTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
 class PermissionAllServicesTest : BasePermissionTest() {
 
     // "All services" screen is not supported on Auto in T
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java b/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java
index db59919..8c62f21 100644
--- a/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java
+++ b/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java
@@ -41,6 +41,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executors;
@@ -50,6 +51,60 @@
 
     private static final String TEST_NUMBER = "5625698388";
     private static final long CONTENT_RESOLVER_TIMEOUT_MS = 5000;
+    private static final Uri INVALID_CALL_LOG_URI = Uri.parse(
+            "content://call_log/call_composer/%2fdata%2fdata%2fcom.android.providers"
+                    + ".contacts%2fshared_prefs%2fContactsUpgradeReceiver.xml");
+
+    private static final String TEST_FAIL_DID_NOT_TRHOW_SE =
+            "fail test because Security Exception was not throw";
+
+    /**
+     * Tests scenario where an app gives {@link ContentResolver} a file to open that is not in the
+     * Call Log directory.
+     */
+    public void testOpenFileOutsideOfScopeThrowsException() throws FileNotFoundException {
+        try {
+            Context context = getInstrumentation().getContext();
+            ContentResolver resolver = context.getContentResolver();
+            resolver.openFile(INVALID_CALL_LOG_URI, "w", null);
+            // previous line should throw exception
+            fail(TEST_FAIL_DID_NOT_TRHOW_SE);
+        } catch (SecurityException e) {
+            assertNotNull(e.toString());
+        }
+    }
+
+    /**
+     * Tests scenario where an app gives {@link ContentResolver} a file to delete that is not in the
+     * Call Log directory.
+     */
+    public void testDeleteFileOutsideOfScopeThrowsException() {
+        try {
+            Context context = getInstrumentation().getContext();
+            ContentResolver resolver = context.getContentResolver();
+            resolver.delete(INVALID_CALL_LOG_URI, "w", null);
+            // previous line should throw exception
+            fail(TEST_FAIL_DID_NOT_TRHOW_SE);
+        } catch (SecurityException e) {
+            assertNotNull(e.toString());
+        }
+    }
+
+    /**
+     * Tests scenario where an app gives {@link ContentResolver} a file to insert outside the
+     * Call Log directory.
+     */
+    public void testInsertFileOutsideOfScopeThrowsException() {
+        try {
+            Context context = getInstrumentation().getContext();
+            ContentResolver resolver = context.getContentResolver();
+            resolver.insert(INVALID_CALL_LOG_URI, new ContentValues());
+            // previous line should throw exception
+            fail(TEST_FAIL_DID_NOT_TRHOW_SE);
+        } catch (SecurityException e) {
+            assertNotNull(e.toString());
+        }
+    }
 
     public void testGetLastOutgoingCall() {
         // Clear call log and ensure there are no outgoing calls
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 863da91..9a691c1 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -5296,6 +5296,10 @@
             Log.i(TAG, "testSetVoiceServiceStateOverride: originalSS = " + originalServiceState);
             assertNotEquals(ServiceState.STATE_IN_SERVICE, originalServiceState);
 
+            // Wait for device to finish processing RADIO_POWER_OFF.
+            // Otherwise, Telecom will clear the voice state override before SST processes it.
+            waitForMs(10000);
+
             // We should see the override reflected by both ServiceStateListener and getServiceState
             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
                     mTelephonyManager,
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
index efd0edb..81850a8 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
@@ -56,6 +56,7 @@
     private static TelephonyManager sTelephonyManager;
     private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
     private static final boolean DEBUG = !"user".equals(Build.TYPE);
+    private static boolean sIsMultiSimDevice;
 
     @BeforeClass
     public static void beforeAllTests() throws Exception {
@@ -69,6 +70,14 @@
         sTelephonyManager =
                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
 
+        sIsMultiSimDevice = isMultiSim(sTelephonyManager);
+
+        //TODO: Support DSDS b/210073692
+        if (sIsMultiSimDevice) {
+            Log.d(TAG, "Not support MultiSIM");
+            return;
+        }
+
         sMockModemManager = new MockModemManager();
         assertNotNull(sMockModemManager);
         assertTrue(sMockModemManager.connectMockModemService());
@@ -82,6 +91,11 @@
             return;
         }
 
+        //TODO: Support DSDS b/210073692
+        if (sIsMultiSimDevice) {
+            return;
+        }
+
         // Rebind all interfaces which is binding to MockModemService to default.
         assertNotNull(sMockModemManager);
         assertTrue(sMockModemManager.disconnectMockModemService());
@@ -91,6 +105,8 @@
     @Before
     public void beforeTest() {
         assumeTrue(hasTelephonyFeature());
+        //TODO: Support DSDS b/210073692
+        assumeTrue(!sIsMultiSimDevice);
     }
 
     private static Context getContext() {
@@ -106,6 +122,10 @@
         return true;
     }
 
+    private static boolean isMultiSim(TelephonyManager tm) {
+        return tm != null && tm.getPhoneCount() > 1;
+    }
+
     private static void enforceMockModemDeveloperSetting() throws Exception {
         boolean isAllowed = SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false);
         // Check for developer settings for user build. Always allow for debug builds
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
index 62f0f01..d678fc0 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
@@ -85,7 +85,7 @@
     public static final int WAIT_FOR_CALL_STATE = 10000;
     public static final int WAIT_FOR_CALL_DISCONNECT = 1000;
     public static final int WAIT_FOR_CALL_CONNECT = 5000;
-    public static final int WAIT_FOR_CALL_STATE_HOLD = 2000;
+    public static final int WAIT_FOR_CALL_STATE_HOLD = 1000;
     public static final int WAIT_FOR_CALL_STATE_RESUME = 1000;
     public static final int WAIT_FOR_CALL_STATE_ACTIVE = 15000;
     public static final int LATCH_WAIT = 0;
@@ -380,8 +380,10 @@
         }
 
         if (sServiceConnector != null && sIsBound) {
+            TestImsService imsService = sServiceConnector.getCarrierService();
             sServiceConnector.disconnectCarrierImsService();
             sIsBound = false;
+            imsService.waitForExecutorFinish();
         }
     }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
index 5d7f1e8..d41f98a 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
@@ -42,7 +42,7 @@
     private static final int LATCH_WAIT = 0;
     private static final int LATCH_MAX = 1;
     private static final int WAIT_FOR_STATE_CHANGE = 1500;
-    private static final int WAIT_FOR_ESTABLISHING = 2500;
+    private static final int WAIT_FOR_ESTABLISHING = 2000;
 
     private final String mCallId = String.valueOf(this.hashCode());
     private final Object mLock = new Object();
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 97fa8f2..88934c6 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
@@ -83,7 +83,9 @@
     public static final int LATCH_UCE_LISTENER_SET = 11;
     public static final int LATCH_UCE_REQUEST_PUBLISH = 12;
     public static final int LATCH_ON_UNBIND = 13;
-    private static final int LATCH_MAX = 14;
+    public static final int LATCH_LAST_MESSAGE_EXECUTE = 14;
+    private static final int LATCH_MAX = 15;
+    private static final int WAIT_FOR_EXIT_TEST = 2000;
     protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
     static {
         for (int i = 0; i < LATCH_MAX; i++) {
@@ -587,7 +589,7 @@
             }
 
             if (sMessageExecutor != null) {
-                sMessageExecutor.getLooper().quit();
+                sMessageExecutor.getLooper().quitSafely();
                 sMessageExecutor = null;
             }
             mSubIDs.clear();
@@ -608,6 +610,14 @@
         }
     }
 
+    public void waitForExecutorFinish() {
+        if (mIsTestTypeExecutor && sMessageExecutor != null) {
+            sMessageExecutor.postDelayed(() -> countDownLatch(LATCH_LAST_MESSAGE_EXECUTE), null ,
+                    WAIT_FOR_EXIT_TEST);
+            waitForLatchCountdown(LATCH_LAST_MESSAGE_EXECUTE);
+        }
+    }
+
     public void setImsServiceCompat() {
         synchronized (mLock) {
             mIsImsServiceCompat = true;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt
index 84f0803..c9bb848 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt
@@ -964,6 +964,9 @@
     }
 
     private fun handleRotation(original: Bitmap, image: String): Bitmap {
+        // ExifInterface does not support GIF.
+        if (image.endsWith("gif")) return original
+
         val inputStream = getAssets().open(image)
         val exifInterface = ExifInterface(inputStream)
         var rotation = 0
diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java
index e9b2429..35a7c12 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewTest.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java
@@ -258,6 +258,7 @@
                 screenshot.getPixel(texturePos.right - 10, texturePos.bottom - 10));
     }
 
+    // TODO(b/229173479): understand why DCI_P3 and BT2020 do not match with certain colors.
     private static Object[] testDataSpaces() {
         return new Integer[]{
             DataSpace.DATASPACE_SCRGB_LINEAR,
@@ -275,7 +276,7 @@
     @Test
     @Parameters(method = "testDataSpaces")
     public void testSDRFromSurfaceViewAndTextureView(int dataSpace) throws Throwable {
-        final int grayishYellow = 0xFFBABAB5;
+        final int grayishYellow = 0xFFBABAB9;
         long converted = Color.convert(grayishYellow, ColorSpace.getFromDataSpace(dataSpace));
 
         final SDRTestActivity activity =
diff --git a/tests/tests/virtualdevice/AndroidTest.xml b/tests/tests/virtualdevice/AndroidTest.xml
index c7db7f5..2f800b8 100644
--- a/tests/tests/virtualdevice/AndroidTest.xml
+++ b/tests/tests/virtualdevice/AndroidTest.xml
@@ -14,6 +14,9 @@
      limitations under the License.
 -->
 <configuration description="Configuration for Virtual Device Manager Tests">
+    <!-- Only run tests if the device under test is SDK version 33 (Android 13) or above. -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
+
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
@@ -26,6 +29,7 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsVirtualDevicesTestCases.apk" />
         <option name="test-file-name" value="CtsVirtualDeviceStreamedTestApp.apk" />
+        <option name="check-min-sdk" value="true" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index 0f1f0e8..a99c533 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -64,6 +64,7 @@
     // Th notification privacy indicator
     private final String PRIVACY_CHIP_PACKAGE_NAME = "com.android.systemui";
     private final String PRIVACY_CHIP_ID = "privacy_chip";
+    private final String CAR_MIC_PRIVACY_CHIP_ID = "mic_privacy_chip";
     private final String PRIVACY_DIALOG_PACKAGE_NAME = "com.android.systemui";
     private final String PRIVACY_DIALOG_CONTENT_ID = "text";
     private final String CAR_PRIVACY_DIALOG_CONTENT_ID = "mic_privacy_panel";
@@ -217,8 +218,9 @@
         mUiDevice.openQuickSettings();
         SystemClock.sleep(UI_WAIT_TIMEOUT);
 
+        String chipId = isCar() ? CAR_MIC_PRIVACY_CHIP_ID : PRIVACY_CHIP_ID;
         final UiObject2 privacyChip =
-                mUiDevice.findObject(By.res(PRIVACY_CHIP_PACKAGE_NAME, PRIVACY_CHIP_ID));
+                mUiDevice.findObject(By.res(PRIVACY_CHIP_PACKAGE_NAME, chipId));
         assertWithMessage("Can not find mic indicator").that(privacyChip).isNotNull();
 
         // Click the privacy indicator and verify the calling app name display status in the dialog.
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
index 1c700b5..dae4da9 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -989,6 +989,8 @@
             return;
         }
 
+        if (!mWifiP2pManager.isSetVendorElementsSupported()) return;
+
         List<ScanResult.InformationElement> ies = new ArrayList<>();
         ies.add(new ScanResult.InformationElement(221, 0,
                 new byte[WifiP2pManager.getP2pMaxAllowedVendorElementsLengthBytes() + 1]));
diff --git a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
index 7a0d6f1..cee9088 100644
--- a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
+++ b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
@@ -38,6 +38,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -808,6 +809,185 @@
     }
 
     @Test
+    public void testCallbackCalledOnceAfterDuplicateCalls() throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        UiTranslationManager manager =
+                sContext.getSystemService(UiTranslationManager.class);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        // Register callback
+        final Executor executor = Executors.newSingleThreadExecutor();
+        UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class);
+        manager.registerUiTranslationStateCallback(executor, mockCallback);
+
+        // Call startTranslation() multiple times; callback should only be called once.
+        // Note: The locales don't change with each call.
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onStarted(any(ULocale.class), any(ULocale.class), any(String.class));
+
+        // Call pauseTranslation() multiple times; callback should only be called once.
+        pauseUiTranslation(contentCaptureContext);
+        pauseUiTranslation(contentCaptureContext);
+        pauseUiTranslation(contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class));
+
+        // Call resumeUiTranslation() multiple times; callback should only be called once.
+        resumeUiTranslation(contentCaptureContext);
+        resumeUiTranslation(contentCaptureContext);
+        resumeUiTranslation(contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onResumed(any(ULocale.class), any(ULocale.class), any(String.class));
+    }
+
+    @Test
+    public void testCallbackCalledForStartTranslationWithDifferentLocales() throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        UiTranslationManager manager =
+                sContext.getSystemService(UiTranslationManager.class);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        // Register callback
+        final Executor executor = Executors.newSingleThreadExecutor();
+        UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class);
+        manager.registerUiTranslationStateCallback(executor, mockCallback);
+
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext,
+                ULocale.ENGLISH, ULocale.FRENCH);
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext,
+                ULocale.ENGLISH, ULocale.GERMAN);
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext,
+                ULocale.ITALIAN, ULocale.GERMAN);
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext,
+                ULocale.JAPANESE, ULocale.KOREAN);
+
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onStarted(eq(ULocale.ENGLISH), eq(ULocale.FRENCH), any(String.class));
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onStarted(eq(ULocale.ENGLISH), eq(ULocale.GERMAN), any(String.class));
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onStarted(eq(ULocale.ITALIAN), eq(ULocale.GERMAN), any(String.class));
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onStarted(eq(ULocale.JAPANESE), eq(ULocale.KOREAN), any(String.class));
+
+        // Calling startTranslation() after pauseTranslation() should invoke the callback even if
+        // the locales are the same as it was before.
+        pauseUiTranslation(contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class));
+
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext,
+                ULocale.JAPANESE, ULocale.KOREAN);
+
+        Mockito.verify(mockCallback, Mockito.times(2))
+                .onStarted(eq(ULocale.JAPANESE), eq(ULocale.KOREAN), any(String.class));
+    }
+
+    @Test
+    public void testCallbackCalledOnStartTranslationAfterPause() throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        UiTranslationManager manager =
+                sContext.getSystemService(UiTranslationManager.class);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        // Register callback
+        final Executor executor = Executors.newSingleThreadExecutor();
+        UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class);
+        manager.registerUiTranslationStateCallback(executor, mockCallback);
+
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onStarted(any(ULocale.class), any(ULocale.class), any(String.class));
+
+        pauseUiTranslation(contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class));
+
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+        // Start after pause invokes onResumed(), NOT onStarted().
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onResumed(any(ULocale.class), any(ULocale.class), any(String.class));
+    }
+
+    @Test
+    public void testCallbackNotCalledOnResumeTranslationAfterStart() throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        UiTranslationManager manager =
+                sContext.getSystemService(UiTranslationManager.class);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        // Register callback
+        final Executor executor = Executors.newSingleThreadExecutor();
+        UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class);
+        manager.registerUiTranslationStateCallback(executor, mockCallback);
+
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.times(1))
+                .onStarted(any(ULocale.class), any(ULocale.class), any(String.class));
+
+        resumeUiTranslation(contentCaptureContext);
+
+        Mockito.verify(mockCallback, Mockito.never())
+                .onResumed(any(ULocale.class), any(ULocale.class), any(String.class));
+    }
+
+    @Test
+    public void testCallbackNotCalledOnPauseOrResumeTranslationWithoutStart() throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        UiTranslationManager manager =
+                sContext.getSystemService(UiTranslationManager.class);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        // Register callback
+        final Executor executor = Executors.newSingleThreadExecutor();
+        UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class);
+        manager.registerUiTranslationStateCallback(executor, mockCallback);
+
+        pauseUiTranslation(contentCaptureContext);
+        resumeUiTranslation(contentCaptureContext);
+
+        Mockito.verifyZeroInteractions(mockCallback);
+    }
+
+    @Test
     public void testVirtualViewUiTranslation() throws Throwable {
         // Enable CTS ContentCaptureService
         CtsContentCaptureService contentcaptureService = enableContentCaptureService();
@@ -956,14 +1136,19 @@
 
     private void startUiTranslation(boolean shouldPadContent, List<AutofillId> views,
             ContentCaptureContext contentCaptureContext) {
+        startUiTranslation(shouldPadContent, views, contentCaptureContext, ULocale.ENGLISH,
+                ULocale.FRENCH);
+    }
+
+    private void startUiTranslation(boolean shouldPadContent, List<AutofillId> views,
+            ContentCaptureContext contentCaptureContext, ULocale sourceLocale,
+            ULocale targetLocale) {
         final UiTranslationManager manager = sContext.getSystemService(UiTranslationManager.class);
         runWithShellPermissionIdentity(() -> {
             // Call startTranslation API
             manager.startTranslation(
-                    new TranslationSpec(ULocale.ENGLISH,
-                            TranslationSpec.DATA_FORMAT_TEXT),
-                    new TranslationSpec(ULocale.FRENCH,
-                            TranslationSpec.DATA_FORMAT_TEXT),
+                    new TranslationSpec(sourceLocale, TranslationSpec.DATA_FORMAT_TEXT),
+                    new TranslationSpec(targetLocale, TranslationSpec.DATA_FORMAT_TEXT),
                     views, contentCaptureContext.getActivityId(),
                     shouldPadContent ? new UiTranslationSpec.Builder().setShouldPadContentForCompat(
                             true).build() : new UiTranslationSpec.Builder().build());